wollnyst
wollnyst

Reputation: 1941

How do I programmatically locate my Google Drive folder using C#?

Similar question as here. Just for Google Drive instead of Dropbox:

How do I programmatically locate my Google Drive folder using C#?

Upvotes: 22

Views: 8461

Answers (2)

entiat
entiat

Reputation: 473

I took Sarath's answer, reworked it to be more resilient (quotes around data source path, null conditional on the reader indexing, additional error checking, "using" so objects are disposed appropriately, added a bunch of comments, and threw in some LINQ (because, linq :-) ).

This particular implementation catches and logs exceptions, and then returns string.Empty on any error...because that's how my current app needs it. Remove the try/catch if your app wants exceptions.

/// <summary>
/// Retrieves the local Google Drive directory, if any.
/// </summary>
/// <returns>Directory, or string.Empty if it can't be found</returns>
public static string GetGoogleDriveDirectory()
{
    try
    {
        // Google Drive's sync database can be in a couple different locations. Go find it. 
        string appDataPath = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
        string dbName = "sync_config.db";
        var pathsToTry = new[] { @"Google\Drive\" + dbName, @"Google\Drive\user_default\"+ dbName };

        string syncDbPath = (from p in pathsToTry
                            where File.Exists(Path.Combine(appDataPath, p))
                            select Path.Combine(appDataPath, p))
                            .FirstOrDefault();
        if (syncDbPath == null)
            throw new FileNotFoundException("Cannot find Google Drive sync database", dbName);

        // Build the connection and sql command
        string conString = string.Format(@"Data Source='{0}';Version=3;New=False;Compress=True;", syncDbPath);
        using (var con = new SQLiteConnection(conString))
        using (var cmd = new SQLiteCommand("select * from data where entry_key='local_sync_root_path'", con))
        {
            // Open the connection and execute the command
            con.Open();
            var reader = cmd.ExecuteReader();
            reader.Read();

            // Extract the data from the reader
            string path = reader["data_value"]?.ToString();
            if (string.IsNullOrWhiteSpace(path))
                throw new InvalidDataException("Cannot read 'local_sync_root_path' from Google Drive configuration db");

            // By default, the path will be prefixed with "\\?\" (unless another app has explicitly changed it).
            // \\?\ indicates to Win32 that the filename may be longer than MAX_PATH (see MSDN). 
            // Parts of .NET (e.g. the File class) don't handle this very well, so remove this prefix.
            if (path.StartsWith(@"\\?\"))
                path = path.Substring(@"\\?\".Length);

            return path;
        }
    }
    catch (Exception ex)
    {
        Trace.TraceError("Cannot determine Google Drive location. Error {0} - {1}", ex.Message, ex.StackTrace);
        return string.Empty;
    }
}

Upvotes: 6

Sarath Nair
Sarath Nair

Reputation: 2868

I personally think, the best way is to access the same file through SQLite3.

string dbFilePath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "Google\\Drive\\sync_config.db");
if (!File.Exists(dbFilePath))
    dbFilePath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "Google\\Drive\\user_default\\sync_config.db");

string csGdrive = @"Data Source="+ dbFilePath + ";Version=3;New=False;Compress=True;";                
SQLiteConnection con = new SQLiteConnection(csGdrive);
con.Open();
SQLiteCommand sqLitecmd = new SQLiteCommand(con);

//To retrieve the folder use the following command text
sqLitecmd.CommandText = "select * from data where entry_key='local_sync_root_path'";

SQLiteDataReader reader = sqLitecmd.ExecuteReader();
reader.Read();
//String retrieved is in the format "\\?\<path>" that's why I have used Substring function to extract the path alone.
Console.WriteLine("Google Drive Folder: " + reader["data_value"].ToString().Substring(4));
con.Dispose();

You can get the SQLite library for .Net from here. Also add reference to System.Data.SQLite and include it in your project to run the above code.

To retrieve the user, relpace entry_key='user_email' from the above code

Upvotes: 19

Related Questions