Device drivers: Explicitly fsync() all files when writing to devices

This commit is contained in:
Kovid Goyal 2013-07-29 22:07:12 +05:30
parent 9c562b35c3
commit 0fdbe5a753
16 changed files with 49 additions and 16 deletions

View File

@ -710,3 +710,7 @@ def ipython(user_ns=None):
from calibre.utils.ipython import ipython from calibre.utils.ipython import ipython
ipython(user_ns=user_ns) ipython(user_ns=user_ns)
def fsync(fileobj):
fileobj.flush()
os.fsync(fileobj.fileno())

View File

@ -8,6 +8,7 @@ import os
import cStringIO import cStringIO
from calibre import fsync
from calibre.devices.usbms.driver import USBMS from calibre.devices.usbms.driver import USBMS
HTC_BCDS = [0x100, 0x0222, 0x0224, 0x0226, 0x227, 0x228, 0x229, 0x0231, 0x9999] HTC_BCDS = [0x100, 0x0222, 0x0224, 0x0226, 0x227, 0x228, 0x229, 0x0231, 0x9999]
@ -400,6 +401,7 @@ class WEBOS(USBMS):
with open(os.path.join(path, 'coverCache', filename + '-medium.jpg'), 'wb') as coverfile: with open(os.path.join(path, 'coverCache', filename + '-medium.jpg'), 'wb') as coverfile:
coverfile.write(coverdata) coverfile.write(coverdata)
fsync(coverfile)
coverdata = getattr(metadata, 'thumbnail', None) coverdata = getattr(metadata, 'thumbnail', None)
if coverdata and coverdata[2]: if coverdata and coverdata[2]:
@ -423,6 +425,7 @@ class WEBOS(USBMS):
with open(os.path.join(path, 'coverCache', filename + with open(os.path.join(path, 'coverCache', filename +
'-small.jpg'), 'wb') as coverfile: '-small.jpg'), 'wb') as coverfile:
coverfile.write(coverdata) coverfile.write(coverdata)
fsync(coverfile)

View File

@ -9,7 +9,7 @@ For usage information run the script.
import StringIO, sys, time, os import StringIO, sys, time, os
from optparse import OptionParser from optparse import OptionParser
from calibre import __version__, __appname__, human_readable from calibre import __version__, __appname__, human_readable, fsync
from calibre.devices.errors import PathError from calibre.devices.errors import PathError
from calibre.devices.errors import ArgumentError, DeviceError, DeviceLocked from calibre.devices.errors import ArgumentError, DeviceError, DeviceLocked
from calibre.customize.ui import device_plugins from calibre.customize.ui import device_plugins
@ -293,6 +293,7 @@ def main():
parser.print_help() parser.print_help()
return 1 return 1
dev.get_file(path, outfile) dev.get_file(path, outfile)
fsync(outfile)
outfile.close() outfile.close()
elif args[1].startswith("dev:"): elif args[1].startswith("dev:"):
try: try:

View File

@ -11,6 +11,7 @@ Device driver for Bookeen's Cybook Gen 3 and Opus and Orizon
import os import os
import re import re
from calibre import fsync
from calibre.constants import isunix from calibre.constants import isunix
from calibre.devices.usbms.driver import USBMS from calibre.devices.usbms.driver import USBMS
import calibre.devices.cybook.t2b as t2b import calibre.devices.cybook.t2b as t2b
@ -50,6 +51,7 @@ class CYBOOK(USBMS):
coverdata = None coverdata = None
with open('%s_6090.t2b' % os.path.join(path, filename), 'wb') as t2bfile: with open('%s_6090.t2b' % os.path.join(path, filename), 'wb') as t2bfile:
t2b.write_t2b(t2bfile, coverdata) t2b.write_t2b(t2bfile, coverdata)
fsync(t2bfile)
@classmethod @classmethod
def can_handle(cls, device_info, debug=False): def can_handle(cls, device_info, debug=False):

View File

@ -9,6 +9,7 @@ Device driver for Hanvon devices
''' '''
import re, os import re, os
from calibre import fsync
from calibre.devices.usbms.driver import USBMS from calibre.devices.usbms.driver import USBMS
def is_alex(device_info): def is_alex(device_info):
@ -123,6 +124,7 @@ class ALEX(N516):
os.makedirs(cdir) os.makedirs(cdir)
with open(cpath, 'wb') as coverfile: with open(cpath, 'wb') as coverfile:
coverfile.write(cover) coverfile.write(cover)
fsync(coverfile)
def delete_books(self, paths, end_session=True): def delete_books(self, paths, end_session=True):
for i, path in enumerate(paths): for i, path in enumerate(paths):

View File

@ -14,7 +14,7 @@ from calibre.ebooks.mobi.reader.mobi6 import MobiReader
from calibre.ebooks.pdb.header import PdbHeaderReader from calibre.ebooks.pdb.header import PdbHeaderReader
from calibre.ebooks.mobi.reader.headers import MetadataHeader from calibre.ebooks.mobi.reader.headers import MetadataHeader
from calibre.utils.logging import default_log from calibre.utils.logging import default_log
from calibre import prints from calibre import prints, fsync
from calibre.constants import DEBUG from calibre.constants import DEBUG
class APNXBuilder(object): class APNXBuilder(object):
@ -80,6 +80,7 @@ class APNXBuilder(object):
# Write the APNX. # Write the APNX.
with open(apnx_path, 'wb') as apnxf: with open(apnx_path, 'wb') as apnxf:
apnxf.write(apnx) apnxf.write(apnx)
fsync(apnxf)
def generate_apnx(self, pages, apnx_meta): def generate_apnx(self, pages, apnx_meta):
apnx = '' apnx = ''

View File

@ -12,7 +12,7 @@ import datetime, os, re, sys, json, hashlib
from calibre.devices.kindle.bookmark import Bookmark from calibre.devices.kindle.bookmark import Bookmark
from calibre.devices.usbms.driver import USBMS from calibre.devices.usbms.driver import USBMS
from calibre import strftime from calibre import strftime, fsync
''' '''
Notes on collections: Notes on collections:
@ -410,6 +410,7 @@ class KINDLE2(KINDLE):
uuid=mh.exth.uuid, cdetype=mh.exth.cdetype)) uuid=mh.exth.uuid, cdetype=mh.exth.cdetype))
with open(thumbfile, 'wb') as f: with open(thumbfile, 'wb') as f:
f.write(coverdata[2]) f.write(coverdata[2])
fsync(f)
def upload_apnx(self, path, filename, metadata, filepath): def upload_apnx(self, path, filename, metadata, filepath):
from calibre.devices.kindle.apnx import APNXBuilder from calibre.devices.kindle.apnx import APNXBuilder

View File

@ -23,7 +23,7 @@ from calibre.devices.kobo.books import Book
from calibre.devices.kobo.books import ImageWrapper from calibre.devices.kobo.books import ImageWrapper
from calibre.devices.mime import mime_type_ext from calibre.devices.mime import mime_type_ext
from calibre.devices.usbms.driver import USBMS, debug_print from calibre.devices.usbms.driver import USBMS, debug_print
from calibre import prints from calibre import prints, fsync
from calibre.ptempfile import PersistentTemporaryFile from calibre.ptempfile import PersistentTemporaryFile
from calibre.constants import DEBUG from calibre.constants import DEBUG
from calibre.utils.config_base import prefs from calibre.utils.config_base import prefs
@ -974,6 +974,7 @@ class KOBO(USBMS):
with open(fpath, 'wb') as f: with open(fpath, 'wb') as f:
f.write(data) f.write(data)
fsync(f)
else: else:
debug_print("ImageID could not be retreived from the database") debug_print("ImageID could not be retreived from the database")
@ -2283,6 +2284,7 @@ class KOBOTOUCH(KOBO):
with open(fpath, 'wb') as f: with open(fpath, 'wb') as f:
f.write(data) f.write(data)
fsync(f)
except Exception as e: except Exception as e:
err = str(e) err = str(e)
debug_print("KoboTouch:_upload_cover - Exception string: %s"%err) debug_print("KoboTouch:_upload_cover - Exception string: %s"%err)

View File

@ -9,8 +9,7 @@ __docformat__ = 'restructuredtext en'
import os import os
from calibre.devices.usbms.driver import USBMS from calibre.devices.usbms.driver import USBMS
from calibre import prints from calibre import fsync
prints
class PALMPRE(USBMS): class PALMPRE(USBMS):
@ -100,6 +99,7 @@ class PDNOVEL(USBMS):
if coverdata and coverdata[2]: if coverdata and coverdata[2]:
with open('%s.jpg' % os.path.join(path, filename), 'wb') as coverfile: with open('%s.jpg' % os.path.join(path, filename), 'wb') as coverfile:
coverfile.write(coverdata[2]) coverfile.write(coverdata[2])
fsync(coverfile)
class PDNOVEL_KOBO(PDNOVEL): class PDNOVEL_KOBO(PDNOVEL):
name = 'Pandigital Kobo device interface' name = 'Pandigital Kobo device interface'
@ -118,6 +118,7 @@ class PDNOVEL_KOBO(PDNOVEL):
os.makedirs(dirpath) os.makedirs(dirpath)
with open(os.path.join(dirpath, filename+'.jpg'), 'wb') as coverfile: with open(os.path.join(dirpath, filename+'.jpg'), 'wb') as coverfile:
coverfile.write(coverdata[2]) coverfile.write(coverdata[2])
fsync(coverfile)
class VELOCITYMICRO(USBMS): class VELOCITYMICRO(USBMS):
@ -190,6 +191,7 @@ class LUMIREAD(USBMS):
os.makedirs(pdir) os.makedirs(pdir)
with open(cfilepath+'.jpg', 'wb') as f: with open(cfilepath+'.jpg', 'wb') as f:
f.write(metadata.thumbnail[-1]) f.write(metadata.thumbnail[-1])
fsync(f)
class ALURATEK_COLOR(USBMS): class ALURATEK_COLOR(USBMS):
@ -334,6 +336,7 @@ class NEXTBOOK(USBMS):
os.makedirs(thumbnail_dir) os.makedirs(thumbnail_dir)
with open(os.path.join(thumbnail_dir, filename+'.jpg'), 'wb') as f: with open(os.path.join(thumbnail_dir, filename+'.jpg'), 'wb') as f:
f.write(metadata.thumbnail[-1]) f.write(metadata.thumbnail[-1])
fsync(f)
''' '''
class MOOVYBOOK(USBMS): class MOOVYBOOK(USBMS):

View File

@ -12,6 +12,7 @@ import os
import cStringIO import cStringIO
from calibre import fsync
from calibre.constants import isosx from calibre.constants import isosx
from calibre.devices.usbms.driver import USBMS from calibre.devices.usbms.driver import USBMS
@ -76,6 +77,7 @@ class NOOK(USBMS):
with open('%s.jpg' % os.path.join(path, filename), 'wb') as coverfile: with open('%s.jpg' % os.path.join(path, filename), 'wb') as coverfile:
coverfile.write(coverdata) coverfile.write(coverdata)
fsync(coverfile)
def sanitize_path_components(self, components): def sanitize_path_components(self, components):
return [x.replace('#', '_') for x in components] return [x.replace('#', '_') for x in components]

View File

@ -8,6 +8,7 @@ Device driver for the SONY devices
import os, time, re import os, time, re
from calibre import fsync
from calibre.devices.usbms.driver import USBMS, debug_print from calibre.devices.usbms.driver import USBMS, debug_print
from calibre.devices.prs505 import MEDIA_XML, MEDIA_EXT, CACHE_XML, CACHE_EXT, \ from calibre.devices.prs505 import MEDIA_XML, MEDIA_EXT, CACHE_XML, CACHE_EXT, \
MEDIA_THUMBNAIL, CACHE_THUMBNAIL MEDIA_THUMBNAIL, CACHE_THUMBNAIL
@ -142,6 +143,7 @@ class PRS505(USBMS):
<cache xmlns="http://www.kinoma.com/FskCache/1"> <cache xmlns="http://www.kinoma.com/FskCache/1">
</cache> </cache>
'''.encode('utf8')) '''.encode('utf8'))
fsync(f)
return True return True
except: except:
import traceback import traceback

View File

@ -9,7 +9,7 @@ import os, time
from base64 import b64decode from base64 import b64decode
from datetime import date from datetime import date
from calibre import prints, guess_type, isbytestring from calibre import prints, guess_type, isbytestring, fsync
from calibre.devices.errors import DeviceError from calibre.devices.errors import DeviceError
from calibre.devices.usbms.driver import debug_print from calibre.devices.usbms.driver import debug_print
from calibre.constants import DEBUG, preferred_encoding from calibre.constants import DEBUG, preferred_encoding
@ -122,6 +122,7 @@ class XMLCache(object):
try: try:
with open(path, 'wb') as f: with open(path, 'wb') as f:
f.write(EMPTY_EXT_CACHE) f.write(EMPTY_EXT_CACHE)
fsync(f)
except: except:
pass pass
if os.access(path, os.W_OK): if os.access(path, os.W_OK):
@ -726,6 +727,7 @@ class XMLCache(object):
'<?xml version="1.0" encoding="UTF-8"?>') '<?xml version="1.0" encoding="UTF-8"?>')
with open(path, 'wb') as f: with open(path, 'wb') as f:
f.write(raw) f.write(raw)
fsync(f)
for i, path in self.ext_paths.items(): for i, path in self.ext_paths.items():
try: try:
@ -737,6 +739,7 @@ class XMLCache(object):
'<?xml version="1.0" encoding="UTF-8"?>') '<?xml version="1.0" encoding="UTF-8"?>')
with open(path, 'wb') as f: with open(path, 'wb') as f:
f.write(raw) f.write(raw)
fsync(f)
# }}} # }}}

View File

@ -15,6 +15,7 @@ import os, time, re
from contextlib import closing from contextlib import closing
from datetime import date from datetime import date
from calibre import fsync
from calibre.devices.errors import DeviceError from calibre.devices.errors import DeviceError
from calibre.devices.usbms.driver import USBMS, debug_print from calibre.devices.usbms.driver import USBMS, debug_print
from calibre.devices.usbms.device import USBDevice from calibre.devices.usbms.device import USBDevice
@ -761,6 +762,7 @@ class PRST1(USBMS):
with open(thumbnail_file_path, 'wb') as f: with open(thumbnail_file_path, 'wb') as f:
f.write(book.thumbnail[-1]) f.write(book.thumbnail[-1])
fsync(f)
query = 'UPDATE books SET thumbnail = ? WHERE _id = ?' query = 'UPDATE books SET thumbnail = ? WHERE _id = ?'
t = (thumbnail_path, book.bookId,) t = (thumbnail_path, book.bookId,)

View File

@ -46,7 +46,7 @@ class UDisks(object):
try: try:
return unicode(d.FilesystemMount('', return unicode(d.FilesystemMount('',
['auth_no_user_interaction', 'rw', 'noexec', 'nosuid', ['auth_no_user_interaction', 'rw', 'noexec', 'nosuid',
'sync', 'nodev', 'uid=%d'%os.geteuid(), 'gid=%d'%os.getegid()])) 'nodev', 'uid=%d'%os.geteuid(), 'gid=%d'%os.getegid()]))
except: except:
# May be already mounted, check # May be already mounted, check
mp = node_mountpoint(str(device_node_path)) mp = node_mountpoint(str(device_node_path))
@ -123,7 +123,7 @@ class UDisks2(object):
def mount(self, device_node_path): def mount(self, device_node_path):
d = self.device(device_node_path) d = self.device(device_node_path)
mount_options = ['rw', 'noexec', 'nosuid', mount_options = ['rw', 'noexec', 'nosuid',
'sync', 'nodev', 'uid=%d'%os.geteuid(), 'gid=%d'%os.getegid()] 'nodev', 'uid=%d'%os.geteuid(), 'gid=%d'%os.getegid()]
try: try:
return unicode(d.Mount( return unicode(d.Mount(
{ {

View File

@ -6,6 +6,7 @@ __docformat__ = 'restructuredtext en'
import os, shutil, time import os, shutil, time
from calibre import fsync
from calibre.devices.errors import PathError from calibre.devices.errors import PathError
from calibre.utils.filenames import case_preserving_open_file from calibre.utils.filenames import case_preserving_open_file
@ -58,14 +59,15 @@ class CLI(object):
dest.seek(0) dest.seek(0)
dest.truncate() dest.truncate()
shutil.copyfileobj(infile, dest) shutil.copyfileobj(infile, dest)
fsync(dest)
#if not check_transfer(infile, dest): raise Exception('Transfer failed') #if not check_transfer(infile, dest): raise Exception('Transfer failed')
if close: if close:
infile.close() infile.close()
return actual_path return actual_path
def munge_path(self, path): def munge_path(self, path):
if path.startswith('/') and not (path.startswith(self._main_prefix) or \ if path.startswith('/') and not (path.startswith(self._main_prefix) or
(self._card_a_prefix and path.startswith(self._card_a_prefix)) or \ (self._card_a_prefix and path.startswith(self._card_a_prefix)) or
(self._card_b_prefix and path.startswith(self._card_b_prefix))): (self._card_b_prefix and path.startswith(self._card_b_prefix))):
path = self._main_prefix + path[1:] path = self._main_prefix + path[1:]
elif path.startswith('carda:'): elif path.startswith('carda:'):

View File

@ -14,7 +14,7 @@ import os, time, json, shutil
from itertools import cycle from itertools import cycle
from calibre.constants import numeric_version from calibre.constants import numeric_version
from calibre import prints, isbytestring from calibre import prints, isbytestring, fsync
from calibre.constants import filesystem_encoding, DEBUG from calibre.constants import filesystem_encoding, DEBUG
from calibre.devices.usbms.cli import CLI from calibre.devices.usbms.cli import CLI
from calibre.devices.usbms.device import Device from calibre.devices.usbms.device import Device
@ -85,10 +85,12 @@ class USBMS(CLI, Device):
location_code, name) location_code, name)
with open(os.path.join(prefix, self.DRIVEINFO), 'wb') as f: with open(os.path.join(prefix, self.DRIVEINFO), 'wb') as f:
f.write(json.dumps(driveinfo, default=to_json)) f.write(json.dumps(driveinfo, default=to_json))
fsync(f)
else: else:
driveinfo = self._update_driveinfo_record({}, prefix, location_code, name) driveinfo = self._update_driveinfo_record({}, prefix, location_code, name)
with open(os.path.join(prefix, self.DRIVEINFO), 'wb') as f: with open(os.path.join(prefix, self.DRIVEINFO), 'wb') as f:
f.write(json.dumps(driveinfo, default=to_json)) f.write(json.dumps(driveinfo, default=to_json))
fsync(f)
return driveinfo return driveinfo
def get_device_information(self, end_session=True): def get_device_information(self, end_session=True):
@ -388,6 +390,7 @@ class USBMS(CLI, Device):
os.makedirs(self.normalize_path(prefix)) os.makedirs(self.normalize_path(prefix))
with open(self.normalize_path(os.path.join(prefix, self.METADATA_CACHE)), 'wb') as f: with open(self.normalize_path(os.path.join(prefix, self.METADATA_CACHE)), 'wb') as f:
json_codec.encode_to_file(f, booklists[listid]) json_codec.encode_to_file(f, booklists[listid])
fsync(f)
write_prefix(self._main_prefix, 0) write_prefix(self._main_prefix, 0)
write_prefix(self._card_a_prefix, 1) write_prefix(self._card_a_prefix, 1)
write_prefix(self._card_b_prefix, 2) write_prefix(self._card_b_prefix, 2)