diff --git a/cmd/liber/liber.go b/cmd/liber/liber.go
index e578ae8bba5f288dfd938f194403739cf980842b..5bbf3360a22f01c74714888a60f24dc4f6f30714 100644
--- a/cmd/liber/liber.go
+++ b/cmd/liber/liber.go
@@ -150,8 +150,9 @@ func doUpdate(db *liber.Database, dir string) {
 }
 
 func doSync(db *liber.Database, remoteAddr string) {
+	storage := liber.NewFileStorage(expandTilde(*bookDir))
 	sc := liber.NewRemoteServer(remoteAddr)
-	if err := db.Sync(sc); err != nil {
+	if err := db.Sync(storage, sc); err != nil {
 		log.Fatal(err)
 	}
 }
@@ -178,8 +179,8 @@ func doSearch(db *liber.Database, query string) {
 }
 
 func doHttpServer(db *liber.Database, addr string) {
-	storage := liber.NewFileStorage(expandTilde(*bookDir), 2)
-	cache := liber.NewFileStorage(filepath.Join(expandTilde(*databaseDir), "cache"), 2)
+	storage := liber.NewRWFileStorage(expandTilde(*bookDir), 2)
+	cache := liber.NewRWFileStorage(filepath.Join(expandTilde(*databaseDir), "cache"), 2)
 	server := liber.NewHttpServer(db, storage, cache, addr)
 	log.Fatal(server.ListenAndServe())
 }
diff --git a/sync.go b/sync.go
index 1787187febe4b95cb2ee1e7e2e712382967a95e0..a0cfcfe8df99b1701a3c5d839627251a3d0dc177 100644
--- a/sync.go
+++ b/sync.go
@@ -23,7 +23,7 @@ const (
 
 type SyncClient interface {
 	DiffRequest(*diffRequest) (*diffResponse, error)
-	SendBook(*Book, []*File) error
+	SendBook(*Book, *FileStorage, []*File) error
 }
 
 type remoteServer struct {
@@ -110,7 +110,7 @@ func addFilePart(w *multipart.Writer, varname, filename, mimeFilename string) er
 }
 
 // SendBook uploads a book to the remote server.
-func (r *remoteServer) SendBook(book *Book, files []*File) error {
+func (r *remoteServer) SendBook(book *Book, storage *FileStorage, files []*File) error {
 	// Create a multipart request with the JSON-encoded metadata
 	// and the actual file contents as two separate mime/multipart
 	// sections.
@@ -125,14 +125,14 @@ func (r *remoteServer) SendBook(book *Book, files []*File) error {
 	for i, f := range files {
 		varname := fmt.Sprintf("book%d", i)
 		filename := fmt.Sprintf("%d%s", book.Id, f.FileType)
-		if err := addFilePart(w, varname, f.Path, filename); err != nil {
+		if err := addFilePart(w, varname, storage.Abs(f.Path), filename); err != nil {
 			w.Close()
 			return err
 		}
 	}
 
 	if book.CoverPath != "" {
-		if err := addFilePart(w, "cover", book.CoverPath, "cover.jpg"); err != nil {
+		if err := addFilePart(w, "cover", storage.Abs(book.CoverPath), "cover.jpg"); err != nil {
 			w.Close()
 			return err
 		}
@@ -220,7 +220,7 @@ func (db *Database) findMissing(srv SyncClient) chan string {
 // Sync the local database with a remote one. This is a one-way
 // synchronization: files missing on the remote side will be uploaded
 // to it.
-func (db *Database) Sync(remote SyncClient) error {
+func (db *Database) Sync(storage *FileStorage, remote SyncClient) error {
 	var wg sync.WaitGroup
 
 	ch := db.findMissing(remote)
@@ -232,7 +232,7 @@ func (db *Database) Sync(remote SyncClient) error {
 				bookid := ParseID(id)
 				if book, err := db.GetBook(bookid); err == nil {
 					if files, err := db.GetBookFiles(bookid); err == nil {
-						if err := remote.SendBook(book, files); err != nil {
+						if err := remote.SendBook(book, storage, files); err != nil {
 							log.Printf("SendBook(%s): %v", id, err)
 						}
 					}
diff --git a/sync_test.go b/sync_test.go
index eebcc0cc68a7e65a8e6c8f36fdbf7b1113e93657..acb7b7e6bd9df90d37a4a0313e63beda98a50344 100644
--- a/sync_test.go
+++ b/sync_test.go
@@ -24,6 +24,7 @@ func TestSync_Sync(t *testing.T) {
 	// Create a temporary directory to store uploads.
 	updir, _ := ioutil.TempDir("", "ebook-upload-")
 	defer os.RemoveAll(updir)
+	clientStorage := NewFileStorage(updir)
 
 	td, db := newTestDatabase(t)
 	defer td.Close()
@@ -49,7 +50,7 @@ func TestSync_Sync(t *testing.T) {
 	defer srv.Close()
 
 	cl := NewRemoteServer(srv.URL)
-	err := db.Sync(cl)
+	err := db.Sync(clientStorage, cl)
 	if err != nil {
 		t.Fatalf("Sync(): %v", err)
 	}