2015-10-08 15:01:46 +00:00
|
|
|
|
|
|
|
import sys
|
|
|
|
|
|
|
|
from allmydata.util.dbutil import get_db, DBError
|
|
|
|
|
|
|
|
|
|
|
|
# magic-folder db schema version 1
|
|
|
|
SCHEMA_v1 = """
|
|
|
|
CREATE TABLE version
|
|
|
|
(
|
|
|
|
version INTEGER -- contains one row, set to 1
|
|
|
|
);
|
|
|
|
|
|
|
|
CREATE TABLE local_files
|
|
|
|
(
|
|
|
|
path VARCHAR(1024) PRIMARY KEY, -- UTF-8 filename relative to local magic folder dir
|
|
|
|
-- note that size is before mtime and ctime here, but after in function parameters
|
|
|
|
size INTEGER, -- ST_SIZE, or NULL if the file has been deleted
|
2015-10-12 18:07:39 +00:00
|
|
|
mtime NUMBER, -- ST_MTIME
|
|
|
|
ctime NUMBER, -- ST_CTIME
|
2015-10-08 15:01:46 +00:00
|
|
|
version INTEGER,
|
|
|
|
last_uploaded_uri VARCHAR(256) UNIQUE, -- URI:CHK:...
|
|
|
|
last_downloaded_uri VARCHAR(256) UNIQUE, -- URI:CHK:...
|
2015-10-12 18:07:39 +00:00
|
|
|
last_downloaded_timestamp TIMESTAMP
|
2015-10-08 15:01:46 +00:00
|
|
|
);
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
|
|
def get_magicfolderdb(dbfile, stderr=sys.stderr,
|
|
|
|
create_version=(SCHEMA_v1, 1), just_create=False):
|
|
|
|
# Open or create the given backupdb file. The parent directory must
|
|
|
|
# exist.
|
|
|
|
try:
|
|
|
|
(sqlite3, db) = get_db(dbfile, stderr, create_version,
|
|
|
|
just_create=just_create, dbname="magicfolderdb")
|
|
|
|
if create_version[1] in (1, 2):
|
|
|
|
return MagicFolderDB(sqlite3, db)
|
|
|
|
else:
|
|
|
|
print >>stderr, "invalid magicfolderdb schema version specified"
|
|
|
|
return None
|
|
|
|
except DBError, e:
|
|
|
|
print >>stderr, e
|
|
|
|
return None
|
|
|
|
|
|
|
|
|
|
|
|
class MagicFolderDB(object):
|
|
|
|
VERSION = 1
|
|
|
|
|
|
|
|
def __init__(self, sqlite_module, connection):
|
|
|
|
self.sqlite_module = sqlite_module
|
|
|
|
self.connection = connection
|
|
|
|
self.cursor = connection.cursor()
|
|
|
|
|
|
|
|
def check_file_db_exists(self, path):
|
|
|
|
"""I will tell you if a given file has an entry in my database or not
|
|
|
|
by returning True or False.
|
|
|
|
"""
|
|
|
|
c = self.cursor
|
|
|
|
c.execute("SELECT size,mtime,ctime"
|
|
|
|
" FROM local_files"
|
|
|
|
" WHERE path=?",
|
|
|
|
(path,))
|
|
|
|
row = self.cursor.fetchone()
|
|
|
|
if not row:
|
|
|
|
return False
|
|
|
|
else:
|
|
|
|
return True
|
|
|
|
|
|
|
|
def get_all_relpaths(self):
|
|
|
|
"""
|
|
|
|
Retrieve a set of all relpaths of files that have had an entry in magic folder db
|
|
|
|
(i.e. that have been downloaded at least once).
|
|
|
|
"""
|
|
|
|
self.cursor.execute("SELECT path FROM local_files")
|
|
|
|
rows = self.cursor.fetchall()
|
|
|
|
return set([r[0] for r in rows])
|
|
|
|
|
|
|
|
def get_last_downloaded_uri(self, relpath_u):
|
|
|
|
"""
|
|
|
|
Return the last downloaded uri recorded in the magic folder db.
|
|
|
|
If none are found then return None.
|
|
|
|
"""
|
|
|
|
c = self.cursor
|
|
|
|
c.execute("SELECT last_downloaded_uri"
|
|
|
|
" FROM local_files"
|
|
|
|
" WHERE path=?",
|
|
|
|
(relpath_u,))
|
|
|
|
row = self.cursor.fetchone()
|
|
|
|
if not row:
|
|
|
|
return None
|
|
|
|
else:
|
|
|
|
return row[0]
|
|
|
|
|
2015-10-28 15:41:48 +00:00
|
|
|
def get_last_uploaded_uri(self, relpath_u):
|
|
|
|
"""
|
|
|
|
Return the last downloaded uri recorded in the magic folder db.
|
|
|
|
If none are found then return None.
|
|
|
|
"""
|
|
|
|
c = self.cursor
|
|
|
|
c.execute("SELECT last_uploaded_uri"
|
|
|
|
" FROM local_files"
|
|
|
|
" WHERE path=?",
|
|
|
|
(relpath_u,))
|
|
|
|
row = self.cursor.fetchone()
|
|
|
|
if not row:
|
|
|
|
return None
|
|
|
|
else:
|
|
|
|
return row[0]
|
|
|
|
|
2015-10-08 15:01:46 +00:00
|
|
|
def get_local_file_version(self, relpath_u):
|
|
|
|
"""
|
|
|
|
Return the version of a local file tracked by our magic folder db.
|
|
|
|
If no db entry is found then return None.
|
|
|
|
"""
|
|
|
|
c = self.cursor
|
|
|
|
c.execute("SELECT version"
|
|
|
|
" FROM local_files"
|
|
|
|
" WHERE path=?",
|
|
|
|
(relpath_u,))
|
|
|
|
row = self.cursor.fetchone()
|
|
|
|
if not row:
|
|
|
|
return None
|
|
|
|
else:
|
|
|
|
return row[0]
|
|
|
|
|
2015-10-12 18:07:39 +00:00
|
|
|
def did_upload_version(self, relpath_u, version, last_uploaded_uri, last_downloaded_uri, last_downloaded_timestamp, pathinfo):
|
2015-10-15 22:02:07 +00:00
|
|
|
print "%r.did_upload_version(%r, %r, %r, %r, %r, %r)" % (self, relpath_u, version, last_uploaded_uri, last_downloaded_uri, last_downloaded_timestamp, pathinfo)
|
2015-10-08 15:01:46 +00:00
|
|
|
try:
|
|
|
|
print "insert"
|
2015-10-12 18:07:39 +00:00
|
|
|
self.cursor.execute("INSERT INTO local_files VALUES (?,?,?,?,?,?,?,?)",
|
|
|
|
(relpath_u, pathinfo.size, pathinfo.mtime, pathinfo.ctime, version, last_uploaded_uri, last_downloaded_uri, last_downloaded_timestamp))
|
2015-10-08 15:01:46 +00:00
|
|
|
except (self.sqlite_module.IntegrityError, self.sqlite_module.OperationalError):
|
|
|
|
print "err... update"
|
|
|
|
self.cursor.execute("UPDATE local_files"
|
2015-10-12 18:07:39 +00:00
|
|
|
" SET size=?, mtime=?, ctime=?, version=?, last_uploaded_uri=?, last_downloaded_uri=?, last_downloaded_timestamp=?"
|
2015-10-08 15:01:46 +00:00
|
|
|
" WHERE path=?",
|
2015-10-12 18:07:39 +00:00
|
|
|
(pathinfo.size, pathinfo.mtime, pathinfo.ctime, version, last_uploaded_uri, last_downloaded_uri, last_downloaded_timestamp, relpath_u))
|
2015-10-08 15:01:46 +00:00
|
|
|
self.connection.commit()
|
2015-10-15 22:02:07 +00:00
|
|
|
print "committed"
|
2015-10-08 15:01:46 +00:00
|
|
|
|
|
|
|
def is_new_file(self, pathinfo, relpath_u):
|
|
|
|
"""
|
|
|
|
Returns true if the file's current pathinfo (size, mtime, and ctime) has
|
|
|
|
changed from the pathinfo previously stored in the db.
|
|
|
|
"""
|
|
|
|
c = self.cursor
|
|
|
|
c.execute("SELECT size, mtime, ctime"
|
|
|
|
" FROM local_files"
|
|
|
|
" WHERE path=?",
|
|
|
|
(relpath_u,))
|
|
|
|
row = self.cursor.fetchone()
|
|
|
|
if not row:
|
|
|
|
return True
|
2015-10-08 19:00:25 +00:00
|
|
|
if not pathinfo.exists and row[0] is None:
|
|
|
|
return False
|
2015-10-08 15:01:46 +00:00
|
|
|
return (pathinfo.size, pathinfo.mtime, pathinfo.ctime) != row
|