diff --git a/anki/media.py b/anki/media.py index c6b577f95..d7750899f 100644 --- a/anki/media.py +++ b/anki/media.py @@ -35,6 +35,15 @@ class MediaManager: self._dir = re.sub("(?i)\.(anki2)$", ".media", self.col.path) if not os.path.exists(self._dir): os.makedirs(self._dir) + try: + self._oldcwd = os.getcwd() + except OSError: + # cwd doesn't exist + self._oldcwd = None + try: + os.chdir(self._dir) + except OSError: + raise Exception("invalidTempFolder") # change database self.connect() @@ -43,6 +52,7 @@ class MediaManager: return path = self.dir()+".db2" create = not os.path.exists(path) + os.chdir(self._dir) self.db = DB(path) if create: self._initDB() @@ -84,16 +94,23 @@ create table meta (dirMod int, lastUsn int); insert into meta values (0, 0); # anew self.col.log("failed to import old media db:"+traceback.format_exc()) self.db.execute("detach old") - npath = os.path.join(self.dir(), "collection.media.db.old") + npath = "../collection.media.db.old" if os.path.exists(npath): os.unlink(npath) - os.rename(os.path.join(self.dir(), "collection.media.db"), npath) + os.rename("../collection.media.db", npath) def close(self): if self.col.server: return self.db.close() self.db = None + # change cwd back to old location + if self._oldcwd: + try: + os.chdir(self._oldcwd) + except: + # may have been deleted + pass def dir(self): return self._dir @@ -243,26 +260,24 @@ create table meta (dirMod int, lastUsn int); insert into meta values (0, 0); files = local renamedFiles = False for file in files: - path = os.path.join(self.dir(), file) if not local: - if not os.path.isfile(path): + if not os.path.isfile(file): # ignore directories continue if file.startswith("_"): # leading _ says to ignore file continue nfcFile = unicodedata.normalize("NFC", file) - nfcPath = os.path.join(self.dir(), nfcFile) # we enforce NFC fs encoding on non-macs; on macs we'll have gotten # NFD so we use the above variable for comparing references if not isMac and not local: if file != nfcFile: # delete if we already have the NFC form, otherwise rename - if os.path.exists(nfcPath): - os.unlink(path) + if os.path.exists(nfcFile): + os.unlink(file) renamedFiles = True else: - os.rename(path, nfcPath) + os.rename(file, nfcFile) renamedFiles = True file = nfcFile # compare @@ -332,9 +347,8 @@ create table meta (dirMod int, lastUsn int); insert into meta values (0, 0); (added, removed) = self._changes() media = [] for f in added: - path = os.path.join(self.dir(), f) - mt = self._mtime(path) - media.append((f, self._checksum(path), mt, 1)) + mt = self._mtime(f) + media.append((f, self._checksum(f), mt, 1)) for f in removed: media.append((f, None, 0, 1)) # update media db @@ -352,9 +366,8 @@ create table meta (dirMod int, lastUsn int); insert into meta values (0, 0); removed = [] # loop through on-disk files for f in os.listdir(self.dir()): - path = os.path.join(self.dir(), f) # ignore folders and thumbs.db - if os.path.isdir(path): + if os.path.isdir(f): continue if f.lower() == "thumbs.db": continue @@ -362,9 +375,9 @@ create table meta (dirMod int, lastUsn int); insert into meta values (0, 0); if self.hasIllegal(f): continue # empty files are invalid; clean them up and continue - sz = os.path.getsize(path) + sz = os.path.getsize(f) if not sz: - os.unlink(path) + os.unlink(f) continue if sz > 100*1024*1024: self.col.log("ignoring file over 100MB", f) @@ -372,21 +385,20 @@ create table meta (dirMod int, lastUsn int); insert into meta values (0, 0); # check encoding if not isMac: normf = unicodedata.normalize("NFC", f) - normpath = os.path.join(self.dir(), normf) if f != normf: # wrong filename encoding which will cause sync errors - if os.path.exists(normpath): - os.unlink(path) + if os.path.exists(normf): + os.unlink(f) else: - os.rename(path, normpath) + os.rename(f, normf) # newly added? if f not in self.cache: added.append(f) else: # modified since last time? - if self._mtime(path) != self.cache[f][1]: + if self._mtime(f) != self.cache[f][1]: # and has different checksum? - if self._checksum(path) != self.cache[f][0]: + if self._checksum(f) != self.cache[f][0]: added.append(f) # mark as used self.cache[f][2] = True @@ -417,9 +429,8 @@ create table meta (dirMod int, lastUsn int); insert into meta values (0, 0); "update media set dirty=0 where fname=?", fname) def syncDelete(self, fname): - path = os.path.join(self.dir(), fname) - if os.path.exists(path): - os.unlink(path) + if os.path.exists(fname): + os.unlink(fname) self.db.execute("delete from media where fname=?", fname) def mediaCount(self): @@ -456,15 +467,14 @@ create table meta (dirMod int, lastUsn int); insert into meta values (0, 0); "select fname, csum from media where dirty=1" " limit %d"%SYNC_ZIP_COUNT)): - path = os.path.join(self.dir(), fname) fnames.append(fname) normname = unicodedata.normalize("NFC", fname) if csum: self.col.log("+media zip", fname) - z.write(path, str(c)) + z.write(fname, str(c)) meta.append((normname, str(c))) - sz += os.path.getsize(path) + sz += os.path.getsize(fname) else: self.col.log("-media zip", fname) meta.append((normname, "")) @@ -499,10 +509,9 @@ create table meta (dirMod int, lastUsn int); insert into meta values (0, 0); else: name = unicodedata.normalize("NFC", name) # save file - path = os.path.join(self.dir(), name) - open(path, "wb").write(data) + open(name, "wb").write(data) # update db - media.append((name, csum, self._mtime(path), 0)) + media.append((name, csum, self._mtime(name), 0)) cnt += 1 if media: self.db.executemany( diff --git a/tests/test_media.py b/tests/test_media.py index 5a2a495c2..7a1c391c5 100644 --- a/tests/test_media.py +++ b/tests/test_media.py @@ -77,30 +77,29 @@ def test_changes(): assert not list(added()) assert not list(removed()) # add a file - tmp_dir = tempfile.mkdtemp(prefix="anki") - tmp_path = os.path.join(tmp_dir, "foo.jpg") - open(tmp_path, "w").write("hello") + dir = tempfile.mkdtemp(prefix="anki") + path = os.path.join(dir, "foo.jpg") + open(path, "w").write("hello") time.sleep(1) - fname = d.media.addFile(tmp_path) - internal_path = os.path.join(d.media.dir(), fname) + path = d.media.addFile(path) # should have been logged d.media.findChanges() assert list(added()) assert not list(removed()) # if we modify it, the cache won't notice time.sleep(1) - open(internal_path, "w").write("world") + open(path, "w").write("world") assert len(list(added())) == 1 assert not list(removed()) # but if we add another file, it will time.sleep(1) - open(internal_path+"2", "w").write("yo") + open(path+"2", "w").write("yo") d.media.findChanges() assert len(list(added())) == 2 assert not list(removed()) # deletions should get noticed too time.sleep(1) - os.unlink(internal_path+"2") + os.unlink(path+"2") d.media.findChanges() assert len(list(added())) == 1 assert len(list(removed())) == 1