Exemplo n.º 1
0
        public static void FurtherDiagnoseDBProblem(Exception ex, List <Exception> corruption_list, string library_path)
        {
            SQLiteException sql_ex = ex as SQLiteException;

            // so we had a failure (or several)... now check the state of the database file and report on our findings:
            StringBuilder sb = new StringBuilder();

            do
            {
                sb.AppendLine("--- Diagnosis for reported problem ---");
                sb.AppendLine("======================================");
                sb.AppendLine("");

                if (!File.Exists(library_path))
                {
                    sb.AppendLine($"--> The database file '{library_path}' does not exist.");
                    break;
                }

                bool looks_sane  = true;
                bool is_readonly = false;

                // what are the access rights and size?
                try
                {
                    var info = File.GetFileSystemEntryInfo(library_path);

                    sb.AppendLine($"--> File Attributes:                                {info.Attributes}");
                    sb.AppendLine($"--> File Creation Date (UTC):                       {info.CreationTimeUtc}");
                    sb.AppendLine($"--> File Last Changed Date (UTC):                   {info.LastWriteTimeUtc}");
                    sb.AppendLine($"--> File Last Access Date (UTC):                    {info.LastAccessTimeUtc}");
                    sb.AppendLine($"--> Is marked as READ ONLY:                         {info.IsReadOnly}");
                    sb.AppendLine($"--> Is marked as OFFLINE:                           {info.IsOffline}");
                    sb.AppendLine($"--> Is marked as archived:                          {info.IsArchive}");
                    sb.AppendLine($"--> Is marked as HIDDEN:                            {info.IsHidden}");
                    sb.AppendLine($"--> Is a SYSTEM FILE:                               {info.IsSystem}");
                    sb.AppendLine($"--> Is encrypted by the operating system:           {info.IsEncrypted}");
                    sb.AppendLine($"--> Is compressed by the operating system:          {info.IsCompressed}");
                    sb.AppendLine($"--> Is a mount point:                               {info.IsMountPoint}");
                    sb.AppendLine($"--> Is temporary:                                   {info.IsTemporary}");
                    sb.AppendLine($"--> Is a symbolic link:                             {info.IsSymbolicLink}");
                    sb.AppendLine($"--> Is a sparse file:                               {info.IsSparseFile}");
                    sb.AppendLine($"--> Is a reparse point:                             {info.IsReparsePoint}");
                    sb.AppendLine($"--> Is not content indexed by the operating system: {info.IsNotContentIndexed}");
                    sb.AppendLine($"--> Is a directory:                                 {info.IsDirectory}");
                    sb.AppendLine($"--> Is a device:                                    {info.IsDevice}");
                    sb.AppendLine($"--> Is a normal file:                               {info.IsNormal}");
                    sb.AppendLine($"--> File size:                                      {info.FileSize} bytes");

                    is_readonly = info.IsReadOnly;

                    if (info.IsOffline || info.IsHidden || info.IsSystem || info.IsEncrypted || info.IsMountPoint || info.IsTemporary || info.IsSymbolicLink || info.IsSparseFile || info.IsReparsePoint || info.IsDirectory || info.IsDevice)
                    {
                        sb.AppendLine("");
                        sb.AppendLine("--> WARNING: this doesn't look like a very normal file.");
                        sb.AppendLine("    Check the attributes above to determine if they are as you expect.");
                        sb.AppendLine("");
                        looks_sane = false;
                    }
                }
                catch (Exception ex2)
                {
                    sb.AppendLine($"--> FAILED to collect the file attributes: {ex2.ToStringAllExceptionDetails()}");
                    looks_sane = false;
                }

                // Check if we can open the file for basic I/O:
                try
                {
                    // read the entire file into a 1M buffer. Watch for errors.
                    byte[]    buf         = new byte[1024 * 1024];
                    const int count       = 1024 * 1024;
                    long      length_read = 0;

                    using (var stream = File.OpenRead(library_path))
                    {
                        int rc;

                        while (true)
                        {
                            rc = stream.Read(buf, 0, count);
                            if (rc > 0)
                            {
                                length_read += rc;
                            }
                            else if (rc == 0)
                            {
                                // EOF
                                break;
                            }
                            else
                            {
                                throw new Exception($"stream.Read produced a negative result: {rc}");
                            }
                        }
                    }

                    long file_size = File.GetSize(library_path);

                    if (file_size != length_read)
                    {
                        throw new Exception($"stream.Read was unable to read/scan the entire file:\n      file size reported by the file system = {file_size} bytes, length scanned = {length_read} bytes");
                    }

                    sb.AppendLine($"--> Successfully scanned the entire file: length scanned = {length_read} bytes");
                }
                catch (Exception ex2)
                {
                    sb.AppendLine($"--> FAILED to read/scan the file: {ex2.ToStringAllExceptionDetails()}");
                    looks_sane = false;
                }

                if (!is_readonly)
                {
                    // check if we can open the file for WRITE access
                    try
                    {
                        using (var stream = File.OpenWrite(library_path))
                        {
                            sb.AppendLine($"--> Successfully opened the file for WRITE ACCESS");
                        }
                    }
                    catch (Exception ex2)
                    {
                        sb.AppendLine($"--> FAILED to open the file for WRITE ACCESS:);");
                        sb.AppendLine(ex2.ToStringAllExceptionDetails());
                        looks_sane = false;
                    }
                }

                if (corruption_list != null && corruption_list.Count > 0)
                {
                    if (looks_sane)
                    {
                        sb.AppendLine("--> WARNING: while the RAW file scan and access checks may have PASSED,");
                        sb.AppendLine("    the Qiqqa inner systems certainly found stuff in the file to complain about:");
                        sb.AppendLine("    these data corruptions (a.k.a. DECODE FAILURES) have already been reported,");
                        sb.AppendLine("    but here they are once more in summarized form:");
                    }
                    else
                    {
                        sb.AppendLine("--> ERROR: while the RAW file scan and access checks may have FAILED,");
                        sb.AppendLine("    the Qiqqa inner systems also found stuff in the file to complain about");
                        sb.AppendLine("    -- which is VERY PROBABLY related to or caused by the findings reported above.");
                        sb.AppendLine("");
                        sb.AppendLine("    The data corruptions (a.k.a. DECODE FAILURES) have already been reported,");
                        sb.AppendLine("    but here they are once more in summarized form:");
                    }
                    sb.AppendLine("");

                    int index = 1;
                    foreach (var corruption in corruption_list)
                    {
                        sb.AppendLine($"      #{index.ToString("03")}: {corruption.Message.Split('\n')[0]}");
                        index++;
                    }
                    sb.AppendLine($"      --- {corruption_list.Count} reported data corruptions ---------------------------------------");

                    looks_sane = false;
                }

                if (sql_ex != null)
                {
                    sb.AppendLine("");
                    sb.AppendLine("    As this report is about a SQLite database error, it MAY be useful to search");
                    sb.AppendLine("    the Internet for generic help and/or discussion of the reported SQLite error:");
                    sb.AppendLine("");
                    int errorcode      = sql_ex.ErrorCode;
                    int basenum        = errorcode & 0xFF;
                    int extended_shift = errorcode >> 8;
                    int herr           = sql_ex.HResult;

                    sb.AppendLine("    ( ref: https://sqlite.org/rescode.html )");
                    sb.AppendLine("    ( ref: https://sqlite.org/c3ref/c_abort.html )");
                    sb.AppendLine($"    SQLite Error Code: {basenum}");
                    if (extended_shift != 0)
                    {
                        sb.AppendLine("    ( ref: https://sqlite.org/c3ref/c_abort_rollback.html )");
                        sb.AppendLine($"    SQLite Extended Error Code: ({basenum} | ({extended_shift} << 8))   = {errorcode}");
                    }
                    else
                    {
                        sb.AppendLine("    Reported error code is NOT a SQLite Extended Error Code.");
                    }
                    sb.AppendLine($"    SQLite HResult: {herr.ToString("08:X")}");
                    sb.AppendLine("");
                    sb.AppendLine($"      SQLite: the define constants (i.e. compile-time options): {SQLiteConnection.DefineConstants}");
                    sb.AppendLine($"      SQLite: the underlying SQLite core library: {SQLiteConnection.SQLiteVersion}");
                    sb.AppendLine($"      SQLite: SQLITE_SOURCE_ID: {SQLiteConnection.SQLiteSourceId}");
                    sb.AppendLine($"      SQLite: the compile-time options: {SQLiteConnection.SQLiteCompileOptions}");
                    sb.AppendLine($"      SQLite: the version of the interop SQLite assembly: {SQLiteConnection.InteropVersion}");
                    sb.AppendLine($"      SQLite: the unique identifier for the source checkout used to build the interop assembly: {SQLiteConnection.InteropSourceId}");
                    sb.AppendLine($"      SQLite: the compile-time options used to compile the SQLite interop assembly: {SQLiteConnection.InteropCompileOptions}");
                    sb.AppendLine($"      SQLite: the version of the managed components: {SQLiteConnection.ProviderVersion}");
                    sb.AppendLine($"      SQLite: the unique identifier for the source checkout used to build the managed components: {SQLiteConnection.ProviderSourceId}");
                    sb.AppendLine($"      SQLite: the extra connection flags: {SQLiteConnection.SharedFlags}");
                    sb.AppendLine($"      SQLite: the default connection flags: {SQLiteConnection.DefaultFlags}");
                    sb.AppendLine("");
                    sb.AppendLine("      (ref: https://sqlite.org/c3ref/extended_result_codes.html )");
                    sb.AppendLine("      SQLite Extended Error Reporting has been ENABLED: SetExtendedResultCodes(true)");
                }

                sb.AppendLine("---------");

                if (looks_sane)
                {
                    sb.AppendLine("");
                    sb.AppendLine("--> VERDICT OK(?): this DOES look like a very normal file.");
                    sb.AppendLine("");
                    sb.AppendLine("    HOWEVER, it may have incorrect a.k.a. 'corrupted' content, which made Qiqqa barf,");
                    sb.AppendLine("    or there's something else going on which this simply diagnosis routine");
                    sb.AppendLine("    is unable to unearth.");
                    sb.AppendLine("");
                    sb.AppendLine("    Please file a report at the Qiqqa issue tracker and include this logging");
                    sb.AppendLine("    for further inspection.");
                }
                else
                {
                    sb.AppendLine("");
                    sb.AppendLine("--> VERDICT BAD(?): as far as this simple diagnostic routine can tell,");
                    sb.AppendLine("    this is NOT an 'okay' file.");
                    sb.AppendLine("");
                    if (is_readonly)
                    {
                        sb.AppendLine("    It MAY be marked READ-ONLY, which MAY be okay in your book, but is certainly");
                        sb.AppendLine("    unexpected here.");
                        sb.AppendLine("");
                    }
                    sb.AppendLine("    There's something going on which this simply diagnosis routine CANNOT diagnose further.");
                    sb.AppendLine("");
                    sb.AppendLine("    Please file a report at the Qiqqa issue tracker and include this logging");
                    sb.AppendLine("    for further inspection.");
                }

                sb.AppendLine("");
                sb.AppendLine("==================== End of diagnostics report ============================================");
            } while (false);

            Logging.Error(sb.ToString());
        }