def save_container(container, path): temp = PersistentTemporaryFile(prefix=('_' if iswindows else '.'), suffix=os.path.splitext(path)[1], dir=os.path.dirname(path)) if hasattr(os, 'fchmod'): # Ensure file permissions and owner information is preserved fno = temp.fileno() try: st = os.stat(path) except EnvironmentError as err: if err.errno != errno.ENOENT: raise # path may not exist if we are saving a copy, in which case we use # the metadata from the original book st = os.stat(container.path_to_ebook) os.fchmod(fno, st.st_mode) try: os.fchown(fno, st.st_uid, st.st_gid) except EnvironmentError as err: if err.errno != errno.EPERM: # ignore chown failure as user could be editing file belonging # to a different user, in which case we really cant do anything # about it short of making the file update non-atomic raise temp.close() temp = temp.name try: container.commit(temp) atomic_rename(temp, path) finally: if os.path.exists(temp): os.remove(temp)
def get_cover(metadata): cdir = os.path.join(cache_dir(), 'icon-theme-covers') try: os.makedirs(cdir) except EnvironmentError as e: if e.errno != errno.EEXIST: raise def path(ext): return os.path.join(cdir, metadata['name'] + '.' + ext) etag_file, cover_file = map(path, 'etag jpg'.split()) def safe_read(path): try: with open(path, 'rb') as f: return f.read() except EnvironmentError as e: if e.errno != errno.ENOENT: raise return b'' etag, cached = safe_read(etag_file), safe_read(cover_file) etag = etag.decode('utf-8') cached, etag = download_cover(metadata['cover-url'], etag, cached) if cached: aname = cover_file + '.atomic' with open(aname, 'wb') as f: f.write(cached) atomic_rename(aname, cover_file) if etag: with open(etag_file, 'wb') as f: f.write(as_bytes(etag)) return cached or b''
def save_container(container, path): temp = PersistentTemporaryFile( prefix=('_' if iswindows else '.'), suffix=os.path.splitext(path)[1], dir=os.path.dirname(path)) if hasattr(os, 'fchmod'): # Ensure file permissions and owner information is preserved fno = temp.fileno() try: st = os.stat(path) except EnvironmentError as err: if err.errno != errno.ENOENT: raise # path may not exist if we are saving a copy, in which case we use # the metadata from the original book st = os.stat(container.path_to_ebook) os.fchmod(fno, st.st_mode) os.fchown(fno, st.st_uid, st.st_gid) temp.close() temp = temp.name try: container.commit(temp) atomic_rename(temp, path) finally: if os.path.exists(temp): os.remove(temp)
def atomic_write(name, raw): bdir, bname = os.path.dirname( os.path.abspath(name)), os.path.basename(name) tname = ('_' if iswindows else '.') + bname with open(os.path.join(bdir, tname), 'wb') as f: f.write(raw) atomic_rename(f.name, name)
def save_container(container, path): temp = PersistentTemporaryFile( prefix=('_' if iswindows else '.'), suffix=os.path.splitext(path)[1], dir=os.path.dirname(path)) if hasattr(os, 'fchmod'): # Ensure file permissions and owner information is preserved fno = temp.fileno() try: st = os.stat(path) except EnvironmentError as err: if err.errno != errno.ENOENT: raise # path may not exist if we are saving a copy, in which case we use # the metadata from the original book st = os.stat(container.path_to_ebook) os.fchmod(fno, st.st_mode) try: os.fchown(fno, st.st_uid, st.st_gid) except EnvironmentError as err: if err.errno != errno.EPERM: # ignore chown failure as user could be editing file belonging # to a different user, in which case we really cant do anything # about it short of making the file update non-atomic raise temp.close() temp = temp.name try: container.commit(temp) atomic_rename(temp, path) finally: if os.path.exists(temp): os.remove(temp)
def write_result(self, res): if self.write_result_to: with tempfile.NamedTemporaryFile(dir=os.path.dirname(self.write_result_to), delete=False) as f: src = f.name f.write(str(res).encode('utf-8')) f.flush() atomic_rename(src, self.write_result_to)
def run_optimizer(file_path, cmd, as_filter=False, input_data=None): file_path = os.path.abspath(file_path) cwd = os.path.dirname(file_path) fd, outfile = tempfile.mkstemp(dir=cwd) try: if as_filter: outf = os.fdopen(fd, 'wb') else: os.close(fd) iname, oname = os.path.basename(file_path), os.path.basename(outfile) def repl(q, r): cmd[cmd.index(q)] = r if not as_filter: repl(True, iname), repl(False, oname) if iswindows: # subprocess in python 2 cannot handle unicode strings that are not # encodeable in mbcs, so we fail here, where it is more explicit, # instead. cmd = [x.encode('mbcs') if isinstance(x, type('')) else x for x in cmd] if isinstance(cwd, type('')): cwd = cwd.encode('mbcs') stdin = subprocess.PIPE if as_filter else None stderr = subprocess.PIPE if as_filter else subprocess.STDOUT creationflags = 0x08 if iswindows else 0 p = subprocess.Popen(cmd, cwd=cwd, stdout=subprocess.PIPE, stderr=stderr, stdin=stdin, creationflags=creationflags) stderr = p.stderr if as_filter else p.stdout if as_filter: src = input_data or open(file_path, 'rb') def copy(src, dest): try: shutil.copyfileobj(src, dest) finally: src.close(), dest.close() inw = Thread(name='CopyInput', target=copy, args=(src, p.stdin)) inw.daemon = True inw.start() outw = Thread(name='CopyOutput', target=copy, args=(p.stdout, outf)) outw.daemon = True outw.start() raw = force_unicode(stderr.read()) if p.wait() != 0: return raw else: try: sz = os.path.getsize(outfile) except EnvironmentError: sz = 0 if sz < 1: return raw shutil.copystat(file_path, outfile) atomic_rename(outfile, file_path) finally: try: os.remove(outfile) except EnvironmentError as err: if err.errno != errno.ENOENT: raise
def save_container(container, path): temp = PersistentTemporaryFile( prefix=('_' if iswindows else '.'), suffix=os.path.splitext(path)[1], dir=os.path.dirname(path)) temp.close() temp = temp.name try: container.commit(temp) atomic_rename(temp, path) finally: if os.path.exists(temp): os.remove(temp)
def create_file_copy(ctx, rd, prefix, library_id, book_id, ext, mtime, copy_func, extra_etag_data=''): ''' We cannot copy files directly from the library folder to the output socket, as this can potentially lock the library for an extended period. So instead we copy out the data from the library folder into a temp folder. We make sure to only do this copy once, using the previous copy, if there have been no changes to the data for the file since the last copy. ''' global rename_counter # Avoid too many items in a single directory for performance base = os.path.join(rd.tdir, 'fcache', (('%x' % book_id)[-3:])) if iswindows: base = '\\\\?\\' + os.path.abspath(base) # Ensure fname is not too long for windows' API bname = '%s-%s-%x.%s' % (prefix, library_id, book_id, ext) if '\\' in bname or '/' in bname: raise ValueError('File components must not contain path separators') fname = os.path.join(base, bname) used_cache = 'no' with lock: previous_mtime = mtimes.get(bname) if previous_mtime is None or previous_mtime < mtime: if previous_mtime is not None: # File exists and may be open, so we cannot change its # contents, as that would lead to corrupted downloads in any # clients that are currently downloading the file. if iswindows: # On windows in order to re-use bname, we have to rename it # before deleting it rename_counter += 1 dname = os.path.join(base, '_%x' % rename_counter) atomic_rename(fname, dname) os.remove(dname) else: os.remove(fname) ans = open_for_write(fname) mtimes[bname] = mtime copy_func(ans) ans.seek(0) else: try: ans = share_open(fname, 'rb') used_cache = 'yes' except EnvironmentError as err: if err.errno != errno.ENOENT: raise ans = open_for_write(fname) mtimes[bname] = mtime copy_func(ans) ans.seek(0) if ctx.testing: rd.outheaders['Used-Cache'] = used_cache rd.outheaders['Tempfile'] = hexlify(fname.encode('utf-8')) return rd.filesystem_file_with_custom_etag(ans, prefix, library_id, book_id, mtime, extra_etag_data)
def create_file_copy(ctx, rd, prefix, library_id, book_id, ext, mtime, copy_func, extra_etag_data=""): """ We cannot copy files directly from the library folder to the output socket, as this can potentially lock the library for an extended period. So instead we copy out the data from the library folder into a temp folder. We make sure to only do this copy once, using the previous copy, if there have been no changes to the data for the file since the last copy. """ global rename_counter # Avoid too many items in a single directory for performance base = os.path.join(rd.tdir, "fcache", (("%x" % book_id)[-3:])) if iswindows: base = "\\\\?\\" + os.path.abspath(base) # Ensure fname is not too long for windows' API bname = "%s-%s-%x.%s" % (prefix, library_id, book_id, ext) if "\\" in bname or "/" in bname: raise ValueError("File components must not contain path separators") fname = os.path.join(base, bname) used_cache = "no" with lock: previous_mtime = mtimes.get(bname) if previous_mtime is None or previous_mtime < mtime: if previous_mtime is not None: # File exists and may be open, so we cannot change its # contents, as that would lead to corrupted downloads in any # clients that are currently downloading the file. if iswindows: # On windows in order to re-use bname, we have to rename it # before deleting it rename_counter += 1 dname = os.path.join(base, "_%x" % rename_counter) atomic_rename(fname, dname) os.remove(dname) else: os.remove(fname) try: ans = share_open(fname, "w+b") except EnvironmentError: try: os.makedirs(base) except EnvironmentError: pass ans = share_open(fname, "w+b") mtimes[bname] = mtime copy_func(ans) ans.seek(0) else: ans = share_open(fname, "rb") used_cache = "yes" if ctx.testing: rd.outheaders["Used-Cache"] = used_cache rd.outheaders["Tempfile"] = hexlify(fname.encode("utf-8")) return rd.filesystem_file_with_custom_etag(ans, prefix, library_id, book_id, mtime, extra_etag_data)
def rollover(self): if self.max_size is None or self.current_pos <= self.max_size: return self.stream.close() for i in xrange(self.history - 1, 0, -1): try: atomic_rename('%s.%d' % (self.filename, i), '%s.%d' % (self.filename, i+1)) except EnvironmentError as e: if e.errno != errno.ENOENT: # the source of the rename does not exist raise atomic_rename(self.filename, '%s.%d' % (self.filename, 1)) self.set_output()
def save_container(container, path): temp = PersistentTemporaryFile(prefix=('_' if iswindows else '.'), suffix=os.path.splitext(path)[1], dir=os.path.dirname(path)) temp.close() temp = temp.name try: container.commit(temp) atomic_rename(temp, path) finally: if os.path.exists(temp): os.remove(temp)
def save_container(container, path): if container.is_dir: return save_dir_container(container, path) temp = PersistentTemporaryFile(prefix=('_' if iswindows else '.'), suffix=os.path.splitext(path)[1], dir=os.path.dirname(path)) if hasattr(os, 'fchmod'): # Ensure file permissions and owner information is preserved fno = temp.fileno() st = None try: st = os.stat(path) except OSError as err: if err.errno != errno.ENOENT: raise # path may not exist if we are saving a copy, in which case we use # the metadata from the original book try: st = os.stat(container.path_to_ebook) except OSError as err: if err.errno != errno.ENOENT: raise # Somebody deleted the original file if st is not None: try: os.fchmod(fno, st.st_mode) except OSError as err: if err.errno != errno.EPERM: raise raise OSError( 'Failed to change permissions of {} to {} ({}), with error: {}. Most likely the {} directory has a restrictive umask' .format(temp.name, oct(st.st_mode), format_permissions(st.st_mode), errno.errorcode[err.errno], os.path.dirname(temp.name))) try: os.fchown(fno, st.st_uid, st.st_gid) except OSError as err: if err.errno not in (errno.EPERM, errno.EACCES): # ignore chown failure as user could be editing file belonging # to a different user, in which case we really can't do anything # about it short of making the file update non-atomic raise temp.close() temp = temp.name try: container.commit(temp) atomic_rename(temp, path) finally: if os.path.exists(temp): os.remove(temp)
def rollover(self): if self.max_size is None or self.current_pos <= self.max_size: return self.stream.close() for i in xrange(self.history - 1, 0, -1): try: atomic_rename('%s.%d' % (self.filename, i), '%s.%d' % (self.filename, i + 1)) except EnvironmentError as e: if e.errno != errno.ENOENT: # the source of the rename does not exist raise atomic_rename(self.filename, '%s.%d' % (self.filename, 1)) self.set_output()
def main(path_to_html, tdir, image_format='jpeg'): if image_format not in ('jpeg', 'png'): raise ValueError('Image format must be either jpeg or png') must_use_qt() path_to_html = os.path.abspath(path_to_html) os.chdir(tdir) renderer = Render() renderer.start_load(path_to_html) ret = QApplication.instance().exec_() if ret == 0: page_images('rendered.pdf', image_format=image_format) ext = {'jpeg': 'jpg'}.get(image_format, image_format) atomic_rename('page-images-1.' + ext, 'rendered.' + image_format) return ret == 0
def do_save(self, tdir, container): temp = None try: path = container.path_to_ebook temp = PersistentTemporaryFile( prefix=('_' if iswindows else '.'), suffix=os.path.splitext(path)[1], dir=os.path.dirname(path)) temp.close() temp = temp.name container.commit(temp) atomic_rename(temp, path) finally: if temp and os.path.exists(temp): os.remove(temp) shutil.rmtree(tdir, ignore_errors=True)
def do_save(self, tdir, container): temp = None try: path = container.path_to_ebook temp = PersistentTemporaryFile(prefix=('_' if iswindows else '.'), suffix=os.path.splitext(path)[1], dir=os.path.dirname(path)) temp.close() temp = temp.name container.commit(temp) atomic_rename(temp, path) finally: if temp and os.path.exists(temp): os.remove(temp) shutil.rmtree(tdir, ignore_errors=True)
def save_container(container, path): if container.is_dir: return save_dir_container(container, path) temp = PersistentTemporaryFile( prefix=('_' if iswindows else '.'), suffix=os.path.splitext(path)[1], dir=os.path.dirname(path)) if hasattr(os, 'fchmod'): # Ensure file permissions and owner information is preserved fno = temp.fileno() st = None try: st = os.stat(path) except EnvironmentError as err: if err.errno != errno.ENOENT: raise # path may not exist if we are saving a copy, in which case we use # the metadata from the original book try: st = os.stat(container.path_to_ebook) except EnvironmentError as err: if err.errno != errno.ENOENT: raise # Somebody deleted the original file if st is not None: try: os.fchmod(fno, st.st_mode) except EnvironmentError as err: if err.errno != errno.EPERM: raise raise EnvironmentError('Failed to change permissions of %s to %s (%s), with error: %s. Most likely the %s directory has a restrictive umask' % ( temp.name, oct(st.st_mode), format_permissions(st.st_mode), errno.errorcode[err.errno], os.path.dirname(temp.name))) try: os.fchown(fno, st.st_uid, st.st_gid) except EnvironmentError as err: if err.errno not in (errno.EPERM, errno.EACCES): # ignore chown failure as user could be editing file belonging # to a different user, in which case we really cant do anything # about it short of making the file update non-atomic raise temp.close() temp = temp.name try: container.commit(temp) atomic_rename(temp, path) finally: if os.path.exists(temp): os.remove(temp)
def save_reading_rates(key, rates): existing = get_existing_reading_rates() existing.pop(key, None) existing[key] = rates while len(existing) > 50: expired = next(iter(existing)) del existing[expired] ddata = json.dumps(existing, indent=2).encode('utf-8') path = reading_rates_path() try: with tempfile.NamedTemporaryFile(dir=os.path.dirname(path), delete=False) as f: f.write(ddata) atomic_rename(f.name, path) except Exception: import traceback traceback.print_exc()
def save_container(container, path): temp = PersistentTemporaryFile( prefix=('_' if iswindows else '.'), suffix=os.path.splitext(path)[1], dir=os.path.dirname(path)) if hasattr(os, 'fchmod'): # Ensure file permissions and owner information is preserved fno = temp.fileno() st = os.stat(path) os.fchmod(fno, st.st_mode) os.fchown(fno, st.st_uid, st.st_gid) temp.close() temp = temp.name try: container.commit(temp) atomic_rename(temp, path) finally: if os.path.exists(temp): os.remove(temp)
def reinit_db(dbpath): from contextlib import closing from calibre import as_unicode from calibre.ptempfile import TemporaryFile from calibre.utils.filenames import atomic_rename # We have to use sqlite3 instead of apsw as apsw has no way to discard # problematic statements import sqlite3 from calibre.library.sqlite import do_connect with TemporaryFile(suffix='_tmpdb.db', dir=os.path.dirname(dbpath)) as tmpdb: with closing(do_connect(dbpath)) as src, closing( do_connect(tmpdb)) as dest: dest.execute( 'create temporary table temp_sequence(id INTEGER PRIMARY KEY AUTOINCREMENT)' ) dest.commit() uv = int(src.execute('PRAGMA user_version;').fetchone()[0]) dump = src.iterdump() last_restore_error = None while True: try: statement = next(dump) except StopIteration: break except sqlite3.OperationalError as e: prints('Failed to dump a line:', as_unicode(e)) if last_restore_error: prints('Failed to restore a line:', last_restore_error) last_restore_error = None try: dest.execute(statement) except sqlite3.OperationalError as e: last_restore_error = as_unicode(e) # The dump produces an extra commit at the end, so # only print this error if there are more # statements to be restored dest.execute('PRAGMA user_version=%d;' % uv) dest.commit() atomic_rename(tmpdb, dbpath) prints('Database successfully re-initialized')
def reinit_db(dbpath): from contextlib import closing from calibre import as_unicode from calibre.ptempfile import TemporaryFile from calibre.utils.filenames import atomic_rename # We have to use sqlite3 instead of apsw as apsw has no way to discard # problematic statements import sqlite3 from calibre.library.sqlite import do_connect with TemporaryFile(suffix="_tmpdb.db", dir=os.path.dirname(dbpath)) as tmpdb: with closing(do_connect(dbpath)) as src, closing(do_connect(tmpdb)) as dest: dest.execute("create temporary table temp_sequence(id INTEGER PRIMARY KEY AUTOINCREMENT)") dest.commit() uv = int(src.execute("PRAGMA user_version;").fetchone()[0]) dump = src.iterdump() last_restore_error = None while True: try: statement = next(dump) except StopIteration: break except sqlite3.OperationalError as e: prints("Failed to dump a line:", as_unicode(e)) if last_restore_error: prints("Failed to restore a line:", last_restore_error) last_restore_error = None try: dest.execute(statement) except sqlite3.OperationalError as e: last_restore_error = as_unicode(e) # The dump produces an extra commit at the end, so # only print this error if there are more # statements to be restored dest.execute("PRAGMA user_version=%d;" % uv) dest.commit() atomic_rename(tmpdb, dbpath) prints("Database successfully re-initialized")
def safe_copy(src, destpath): tpath = destpath + '-temp' with open(tpath, 'wb') as dest: shutil.copyfileobj(src, dest) atomic_rename(tpath, destpath)
def run_optimizer(file_path, cmd, as_filter=False, input_data=None): file_path = os.path.abspath(file_path) cwd = os.path.dirname(file_path) ext = os.path.splitext(file_path)[1] if not ext or len(ext) > 10 or not ext.startswith("."): ext = ".jpg" fd, outfile = tempfile.mkstemp(dir=cwd, suffix=ext) try: if as_filter: outf = os.fdopen(fd, "wb") else: os.close(fd) iname, oname = os.path.basename(file_path), os.path.basename(outfile) def repl(q, r): cmd[cmd.index(q)] = r if not as_filter: repl(True, iname), repl(False, oname) if iswindows: # subprocess in python 2 cannot handle unicode strings that are not # encodeable in mbcs, so we fail here, where it is more explicit, # instead. cmd = [x.encode("mbcs") if isinstance(x, type("")) else x for x in cmd] if isinstance(cwd, type("")): cwd = cwd.encode("mbcs") stdin = subprocess.PIPE if as_filter else None stderr = subprocess.PIPE if as_filter else subprocess.STDOUT creationflags = 0x08 if iswindows else 0 p = subprocess.Popen( cmd, cwd=cwd, stdout=subprocess.PIPE, stderr=stderr, stdin=stdin, creationflags=creationflags ) stderr = p.stderr if as_filter else p.stdout if as_filter: src = input_data or open(file_path, "rb") def copy(src, dest): try: shutil.copyfileobj(src, dest) finally: src.close(), dest.close() inw = Thread(name="CopyInput", target=copy, args=(src, p.stdin)) inw.daemon = True inw.start() outw = Thread(name="CopyOutput", target=copy, args=(p.stdout, outf)) outw.daemon = True outw.start() raw = force_unicode(stderr.read()) if p.wait() != 0: return raw else: if as_filter: outw.join(60.0), inw.join(60.0) try: sz = os.path.getsize(outfile) except EnvironmentError: sz = 0 if sz < 1: return "%s returned a zero size image" % cmd[0] shutil.copystat(file_path, outfile) atomic_rename(outfile, file_path) finally: try: os.remove(outfile) except EnvironmentError as err: if err.errno != errno.ENOENT: raise try: os.remove(outfile + ".bak") # optipng creates these files except EnvironmentError as err: if err.errno != errno.ENOENT: raise
def atomic_write(name, content): name = os.path.join(base, name) tname = name + '.tmp' with lopen(tname, 'wb') as f: f.write(content) atomic_rename(tname, name)
def run_optimizer(file_path, cmd, as_filter=False, input_data=None): file_path = os.path.abspath(file_path) cwd = os.path.dirname(file_path) ext = os.path.splitext(file_path)[1] if not ext or len(ext) > 10 or not ext.startswith('.'): ext = '.jpg' fd, outfile = tempfile.mkstemp(dir=cwd, suffix=ext) try: if as_filter: outf = os.fdopen(fd, 'wb') else: os.close(fd) iname, oname = os.path.basename(file_path), os.path.basename(outfile) def repl(q, r): cmd[cmd.index(q)] = r if not as_filter: repl(True, iname), repl(False, oname) if iswindows: # subprocess in python 2 cannot handle unicode strings that are not # encodeable in mbcs, so we fail here, where it is more explicit, # instead. cmd = [ x.encode('mbcs') if isinstance(x, type('')) else x for x in cmd ] if isinstance(cwd, type('')): cwd = cwd.encode('mbcs') stdin = subprocess.PIPE if as_filter else None stderr = subprocess.PIPE if as_filter else subprocess.STDOUT creationflags = 0x08 if iswindows else 0 p = subprocess.Popen(cmd, cwd=cwd, stdout=subprocess.PIPE, stderr=stderr, stdin=stdin, creationflags=creationflags) stderr = p.stderr if as_filter else p.stdout if as_filter: src = input_data or open(file_path, 'rb') def copy(src, dest): try: shutil.copyfileobj(src, dest) finally: src.close(), dest.close() inw = Thread(name='CopyInput', target=copy, args=(src, p.stdin)) inw.daemon = True inw.start() outw = Thread(name='CopyOutput', target=copy, args=(p.stdout, outf)) outw.daemon = True outw.start() raw = force_unicode(stderr.read()) if p.wait() != 0: return raw else: if as_filter: outw.join(60.0), inw.join(60.0) try: sz = os.path.getsize(outfile) except EnvironmentError: sz = 0 if sz < 1: return '%s returned a zero size image' % cmd[0] shutil.copystat(file_path, outfile) atomic_rename(outfile, file_path) finally: try: os.remove(outfile) except EnvironmentError as err: if err.errno != errno.ENOENT: raise try: os.remove(outfile + '.bak') # optipng creates these files except EnvironmentError as err: if err.errno != errno.ENOENT: raise
def atomic_write(name, raw): bdir, bname = os.path.dirname(os.path.abspath(name)), os.path.basename(name) tname = ('_' if iswindows else '.') + bname with open(os.path.join(bdir, tname), 'wb') as f: f.write(raw) atomic_rename(f.name, name)