/// <summary> /// Get/create a named lock based on 'dbFullPath' /// Same 'dbFullPath' will get the same lock /// /// </summary> internal static SqlFsLocker getFsLocker(string dbFullPath) { lock (typeof(SqlFsLocker)) { if (lockerTable == null) { lockerTable = new Dictionary <string, SqlFsLocker>(); } if (refCountTable == null) { refCountTable = new Dictionary <string, int?>(); } string tableKey = SqlFsFunc.genHash(dbFullPath); SqlFsLocker locker = lockerTable[tableKey]; if (locker == null) { locker = new SqlFsLocker(tableKey); lockerTable[tableKey] = locker; refCountTable[tableKey] = 1; // reference count 1 } else { // increase reference count by 1 int?count = refCountTable[tableKey]; refCountTable[tableKey] = (int)count + 1; } return(locker); } }
/// <summary> /// Get a single info /// </summary> /// <returns> info value </returns> private string __getInfo(string infoName) { string value = null; string @where = SqlStr.genWhere(new SqlStr.SqlSimpCond(FSINFO.infoName.ToString(), "=", infoName)); Cursor c = null; try { c = db.query(DBNAMES.FsInfo.ToString(), new string[] { FSINFO.infoVal.ToString() }, @where, null, null, null, null); if (c != null && c.moveToFirst()) { value = c.getString(0); } } catch (SQLiteException e) { SqlFsLog.debug(e); SqlFsErrCode.CurrentError = FsErr.GetFsInfoErr; } finally { SqlFsFunc.close(c); } return(value); }
/// @param [in] absolute filePath -- e.g. "/path/to/file" </param> private SqlFile __getFile(string filePath) { if (SqlFsFunc.isNullOrEmpty(filePath)) { SqlFsErrCode.CurrentError = FsErr.EmptyString; return(null); } if (!filePath.StartsWith(SqlFsConst.STRPATHSEP)) // must start with '/' { SqlFsErrCode.CurrentError = FsErr.MustUseAbsolutePath; return(null); } filePath = SqlFsFunc.Trim(filePath, new char[] { SqlFsConst.PATHSEP }); SqlDir rootDir = RootDir; if (rootDir == null) { SqlFsErrCode.CurrentError = FsErr.CannotAccessRoot; return(null); } return(rootDir.getFile(filePath)); }
/// <summary> /// Test if a absolute path (dir/file) exists /// </summary> private bool __exists(string path) { if (SqlFsFunc.isNullOrEmpty(path)) { SqlFsErrCode.CurrentError = FsErr.EmptyString; return(false); } if (!path.StartsWith(SqlFsConst.STRPATHSEP)) // must start with '/' { SqlFsErrCode.CurrentError = FsErr.MustUseAbsolutePath; return(false); } path = SqlFsFunc.Trim(path, new char[] { SqlFsConst.PATHSEP }); if (SqlFsFunc.isNullOrEmpty(path)) // if empty after trim, it refers to root { return(true); } SqlDir rootDir = RootDir; if (rootDir == null) { SqlFsErrCode.CurrentError = FsErr.CannotAccessRoot; return(false); } SqlFsNode fsNode = rootDir.getFsNode(path); return(fsNode != null); }
/// @param [in] absolute dirPath -- e.g. "/path/to/dir" </param> private SqlDir __getDir(string dirPath) { if (SqlFsFunc.isNullOrEmpty(dirPath)) { SqlFsErrCode.CurrentError = FsErr.EmptyString; return(null); } if (!dirPath.StartsWith(SqlFsConst.STRPATHSEP)) // must start with '/' { SqlFsErrCode.CurrentError = FsErr.MustUseAbsolutePath; return(null); } dirPath = SqlFsFunc.Trim(dirPath, new char[] { SqlFsConst.PATHSEP }); SqlDir rootDir = RootDir; if (rootDir == null) { SqlFsErrCode.CurrentError = FsErr.CannotAccessRoot; return(null); } if (SqlFsFunc.isNullOrEmpty(dirPath)) // if empty after trim, it refers to root { return(rootDir); } return(rootDir.getDir(dirPath)); }
/// <summary> /// Get the last (autoIncrement) rowID after a 'INSERT' /// </summary> internal static FsID getLastInsertID(SQLiteDatabase db) { // retrieve the ID of the new entry FsID newID = SqlFsConst.INVALIDID; string sql = "SELECT last_insert_rowid() as [id]"; Cursor c = null; try { c = db.rawQuery(sql, null); if (c.moveToFirst()) { newID = SqlFsFunc.getID(c, 0); } } catch (Exception e) { SqlFsLog.debug(e); SqlFsErrCode.CurrentError = FsErr.GetLastInsertIDError; } finally { SqlFsFunc.close(c); } return(newID); }
//////////////////////////FS operations /////////////////////////////////// /// @param [in] id -- get entry using ID directly </param> internal static SqlFsNode getFsNodeByID(SQLiteDatabase db, SqlFsLocker fsLocker, FsID id) { SqlFsNode fsNode = null; string @where = SqlStr.genWhere(new SqlStr.SqlSimpCond(SqlFs.FSBLOCK.fsID.ToString(), "=", id)); Cursor c = null; try { c = db.query(SqlFs.DBNAMES.FsBlock.ToString(), new string[] { SqlFs.FSBLOCK.fsID.ToString(), SqlFs.FSBLOCK.fsType.ToString() }, @where, null, null, null, null); if (c.moveToFirst()) { fsNode = SqlFsNode.getFsNode(db, fsLocker, c); } } catch (Exception e) { SqlFsLog.debug(e); SqlFsErrCode.CurrentError = FsErr.GetFieldError; } finally { SqlFsFunc.close(c); } return(fsNode); }
/// <summary> /// Check if a dir/file name contains invalid character /// </summary> /// @param [in] name -- contains dir/file name to be checked /// on return, it contains a whitespace-trimmed version /// </param> /// <returns> null -- contains invalid characters </returns> /// <returns> String -- may be modified name </returns> protected internal virtual string checkInvalidChars(string name) { if (SqlFsFunc.isNullOrEmpty(name)) { return(null); } string trimmedStr = SqlFsFunc.Trim(name, SqlFsConst.CHARSTOTRIM); if (SqlFsFunc.isNullOrEmpty(trimmedStr)) // check once again { return(null); } if (SqlFsFunc.indexOfAny(trimmedStr, SqlFsConst.INVALIDCHARS) >= 0) { return(null); } if (trimmedStr.Equals(SqlFsConst.CURDIR)) // can't be '.' { return(null); } if (trimmedStr.Equals(SqlFsConst.PARENTDIR)) // can't be '..' { return(null); } return(trimmedStr); }
/// <summary> /// Create a new entry in FsBlock /// </summary> /// <returns> new ID for the inserted node </returns> internal static FsID addFsNode(SQLiteDatabase db, SqlFsConst.FSTYPE type, string dirName, FsID parentID) { long curTime = SqlFsFunc.calToFileTime(new DateTime()); List <object> colsAndValues = new List <object>(10); colsAndValues.Add(SqlFs.FSBLOCK.fsCreateTime.ToString()); colsAndValues.Add(curTime); colsAndValues.Add(SqlFs.FSBLOCK.fsLastModTime.ToString()); colsAndValues.Add(curTime); colsAndValues.Add(SqlFs.FSBLOCK.fsFileSize.ToString()); colsAndValues.Add(0); colsAndValues.Add(SqlFs.FSBLOCK.fsType.ToString()); colsAndValues.Add(type.v()); colsAndValues.Add(SqlFs.FSBLOCK.fsName.ToString()); colsAndValues.Add(dirName); colsAndValues.Add(SqlFs.FSBLOCK.fsParent.ToString()); colsAndValues.Add(parentID); ContentValues contValues = SqlStr.genContentValues(colsAndValues); try { db.insert(SqlFs.DBNAMES.FsBlock.ToString(), null, contValues); } catch (Exception e) { SqlFsLog.debug(e); SqlFsErrCode.CurrentError = FsErr.AddFsNodeError; return(SqlFsConst.INVALIDID); } // retrieve the ID of the new entry return(SqlFs.getLastInsertID(db)); }
/// @param [in] relative filePath -- e.g. "path/to/file" </param> private SqlFile __getFile(string filePath) { if (SqlFsFunc.isNullOrEmpty(filePath)) { SqlFsErrCode.CurrentError = FsErr.EmptyString; return(null); } if (filePath.StartsWith(SqlFsConst.STRPATHSEP) || filePath.EndsWith(SqlFsConst.STRPATHSEP)) // must *NOT* start or end with '/' { SqlFsErrCode.CurrentError = FsErr.MustNotStartOrEndWithPathSeparator; return(null); } string[] dirSeg = filePath.Split(SqlFsConst.STRPATHSEP, true); if (dirSeg == null || dirSeg.Length <= 0) { SqlFsErrCode.CurrentError = FsErr.SplitPathErr; return(null); } SqlFsNode curNode = this; // start looping to target file for (int i = 0; i < dirSeg.Length; ++i) { if (SqlFsFunc.isNullOrEmpty(dirSeg[i])) // to prevent empty space between separator { continue; } curNode = ((SqlDir)curNode).__getChild(dirSeg[i]); if (i == dirSeg.Length - 1) { if (curNode == null || curNode.Dir) // last one must be a file { curNode = null; SqlFsErrCode.CurrentError = FsErr.ChildNotFound; break; } } else { if (curNode == null || !curNode.Dir) // others' should be dir { curNode = null; SqlFsErrCode.CurrentError = FsErr.NotDirInPath; break; } } } return((SqlFile)curNode); }
/// @param [in] relative dirPath -- e.g. "path/to/dir" </param> private SqlFsNode __getFsNode(string path) { if (SqlFsFunc.isNullOrEmpty(path)) { SqlFsErrCode.CurrentError = FsErr.EmptyString; return(null); } if (path.StartsWith(SqlFsConst.STRPATHSEP)) // must *NOT* start with '/' { SqlFsErrCode.CurrentError = FsErr.MustUseRelativePath; return(null); } if (path.EndsWith(SqlFsConst.STRPATHSEP)) // trim trailing '/' { path = SqlFsFunc.trimEnd(path, new char[] { SqlFsConst.PATHSEP }); } string[] pathSeg = path.Split(SqlFsConst.STRPATHSEP, true); if (pathSeg == null || pathSeg.Length <= 0) { SqlFsErrCode.CurrentError = FsErr.SplitPathErr; return(null); } SqlFsNode curNode = this; // start looping to target node for (int i = 0; i < pathSeg.Length; ++i) { if (SqlFsFunc.isNullOrEmpty(pathSeg[i])) // to prevent empty space between separator { continue; } curNode = ((SqlDir)curNode).__getChild(pathSeg[i]); if (curNode == null) { SqlFsErrCode.CurrentError = FsErr.ChildNotFound; break; } if (!curNode.Dir && i != pathSeg.Length - 1) // if a file but not reach the end yet { curNode = null; SqlFsErrCode.CurrentError = FsErr.NotDirInPath; break; } } return(curNode); }
/// <summary> /// Check existence of tables /// </summary> /// <returns> true -- all tables present </returns> /// <returns> false -- should create new tables </returns> private bool checkTables() { int tabCount = 0; string @where = SqlStr.genWhere(new SqlStr.SqlSimpCond(DBNAMES.type.ToString(), "=", DBNAMES.table.ToString()) ); Cursor c = db.query(DBNAMES.SQLITE_MASTER.ToString(), new string[] { DBNAMES.name.ToString() }, @where, null, null, null, null); // retrieve all table names and check against our list if (c != null && c.moveToFirst()) { do { string tabName = c.getString(0); foreach (string n in TABLIST) { if (n.Equals(tabName, StringComparison.CurrentCultureIgnoreCase)) { tabCount += 1; break; } } } while (c.moveToNext()); } SqlFsFunc.close(c); bool isCheckingOK = false; do { // not all tables exists, may be some corruption ... if (tabCount < TABLIST.Length) { break; } // may be more checking here ... isCheckingOK = true; } while (false); if (tabCount != 0 && !isCheckingOK) { close(); backup(); open(); } return(isCheckingOK); }
/// @param [in] relative dirPath -- e.g. "path/to/dir" </param> private SqlDir __getDir(string dirPath) { if (SqlFsFunc.isNullOrEmpty(dirPath)) { SqlFsErrCode.CurrentError = FsErr.EmptyString; return(null); } if (dirPath.StartsWith(SqlFsConst.STRPATHSEP)) // must *NOT* start with '/' { SqlFsErrCode.CurrentError = FsErr.MustUseRelativePath; return(null); } if (dirPath.EndsWith(SqlFsConst.STRPATHSEP)) // trim trailing '/' { dirPath = SqlFsFunc.trimEnd(dirPath, new char[] { SqlFsConst.PATHSEP }); } string[] dirSeg = dirPath.Split(SqlFsConst.STRPATHSEP, true); if (dirSeg == null || dirSeg.Length <= 0) { SqlFsErrCode.CurrentError = FsErr.SplitPathErr; return(null); } SqlFsNode curNode = this; // start looping to target dir foreach (string dir in dirSeg) { if (SqlFsFunc.isNullOrEmpty(dir)) // to prevent empty space between separator { continue; } curNode = ((SqlDir)curNode).__getChild(dir); if (curNode == null || !curNode.Dir) { curNode = null; SqlFsErrCode.CurrentError = FsErr.ChildNotFound; break; } } return((SqlDir)curNode); }
/// <summary> /// Save field to DB using ID /// </summary> private bool __setField(SqlFs.FSBLOCK field, object val) { List <object> colsAndValues = new List <object>(4); switch (field) { case com.sss.sqlfs.SqlFs.FSBLOCK.fsFileSize: case com.sss.sqlfs.SqlFs.FSBLOCK.fsType: case com.sss.sqlfs.SqlFs.FSBLOCK.fsName: case com.sss.sqlfs.SqlFs.FSBLOCK.fsParent: colsAndValues.Add(field.ToString()); colsAndValues.Add(val); break; case com.sss.sqlfs.SqlFs.FSBLOCK.fsChild: sbyte[] blob = idList2Blob((List <FsID>)val); colsAndValues.Add(field.ToString()); colsAndValues.Add(blob); break; } // update last mod time as well colsAndValues.Add(SqlFs.FSBLOCK.fsLastModTime.ToString()); colsAndValues.Add(SqlFsFunc.calToFileTime(new DateTime())); ContentValues contValues = SqlStr.genContentValues(colsAndValues); string @where = SqlStr.genWhere(new SqlStr.SqlSimpCond(SqlFs.FSBLOCK.fsID.ToString(), "=", this.ID)); int rowAffected = 0; try { rowAffected = db.update(SqlFs.DBNAMES.FsBlock.ToString(), contValues, @where, null); } catch (Exception e) { SqlFsLog.debug(e); SqlFsErrCode.CurrentError = FsErr.SetFieldError; } return(rowAffected > 0); }
/// <summary> /// Move itself to a destination path (absolute or relative) /// </summary> private bool __move(string destPath) { if (SqlFsFunc.isNullOrEmpty(destPath)) { SqlFsErrCode.CurrentError = FsErr.EmptyString; return(false); } // determine destination dir SqlDir destDir = null; if (destPath.StartsWith(SqlFsConst.STRPATHSEP)) { // absolute path SqlDir rootDir = (SqlDir)SqlFs.getFsNodeByID(db, fsLocker, SqlFsConst.ROOTDIRID); // get root destPath = SqlFsFunc.Trim(destPath, new char[] { SqlFsConst.PATHSEP }); // if empty after trim, it refers to root destDir = SqlFsFunc.isNullOrEmpty(destPath) ? rootDir : rootDir.getDir(destPath); } else { // relative path SqlDir parent = this.Parent; if (parent != null) { destDir = parent.getDir(destPath); } } if (destDir != null) { return(__move(destDir)); } SqlFsErrCode.CurrentError = FsErr.DestDirNotFound; return(false); }
internal static SqlDir getDir(SQLiteDatabase db, SqlFsLocker fsLocker, Cursor c) { FsID id = SqlFsFunc.getID(c, SqlFs.FSBLOCK.fsID.ordinal()); return(SqlDir.getDir(db, fsLocker, id)); }
/// <summary> /// Get a field from DB using ID /// </summary> private object __getField(SqlFs.FSBLOCK field) { string @where = SqlStr.genWhere(new SqlStr.SqlSimpCond(SqlFs.FSBLOCK.fsID.ToString(), "=", this.ID)); // little adjustment SqlFs.FSBLOCK tField = (field == SqlFs.FSBLOCK.fsChildCount) ? SqlFs.FSBLOCK.fsChild : field; Cursor c = null; object val = null; try { c = db.query(SqlFs.DBNAMES.FsBlock.ToString(), new string[] { tField.ToString() }, @where, null, null, null, null); if (c.moveToFirst() && !c.isNull(0)) { switch (field) { case com.sss.sqlfs.SqlFs.FSBLOCK.fsCreateTime: case com.sss.sqlfs.SqlFs.FSBLOCK.fsLastModTime: val = c.getLong(0); break; case com.sss.sqlfs.SqlFs.FSBLOCK.fsFileSize: case com.sss.sqlfs.SqlFs.FSBLOCK.fsType: val = c.getInt(0); break; case com.sss.sqlfs.SqlFs.FSBLOCK.fsName: val = c.getString(0); break; case com.sss.sqlfs.SqlFs.FSBLOCK.fsParent: val = SqlFsFunc.getID(c, 0); break; case com.sss.sqlfs.SqlFs.FSBLOCK.fsChild: { sbyte[] buf = c.getBlob(0); val = blob2idList(buf); } break; case com.sss.sqlfs.SqlFs.FSBLOCK.fsChildCount: { sbyte[] buf = c.getBlob(0); val = buf.Length / FsID.IDSize; } break; } } else { val = __getDefaultValue(field); } } catch (Exception e) { SqlFsLog.debug(e); SqlFsErrCode.CurrentError = FsErr.GetFieldError; val = __getDefaultValue(field); // return a default value here } finally { SqlFsFunc.close(c); } return(val); }