An innovative FUSE wrapper for Google Drive.
Switch branches/tags
Clone or download
Pull request Compare This branch is 149 commits behind dsoprea:master.
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Failed to load latest commit information.
dev
gdrivefs.egg-info
gdrivefs
geventhttpclient
tests
tools
.gitignore
LICENSE
MANIFEST
README.md
UBUNTU_QUICKSTART.txt
requirements.txt
setup.py

README.md

GDriveFS

An innovative FUSE wrapper for Google Drive developed under Python 2.7.

I could use some help in testing GDriveFS. Please let me know if you find issues.

Design goals:

Goal Done
Thread for monitoring changes via "changes" functionality of API. X
Complete stat() implementation. X
Seamlessly work around duplicate-file allowances in Google Drive. X
Seamlessly manage file-type versatility in Google Drive (Google Doc files do not have a particular format). X
Allow for the same file at multiple paths. X

Also, a design choice of other implementations is to make the user get API keys for Google Drive, and this doesn't make sense. Our implementation is built against OAuth 2.0 as a native application. You should just have to visit the authorization URL once, plug-in the auth-code, and be done with it.

IMPORTANT

Both PyPI and the Google Code downloads for google_api_python_client have an old version of their libraries, prior to when they fixed some Unicode problems that might cause failure when dealing with downloads/uploads of certain types of files.

To install from Mercurial, do the following:

$ hg clone https://code.google.com/p/google-api-python-client

$ cd google-api-python-client
$ sudo python setup.py install
$ sudo python setup.py install_egg_info

NOTE: I've also experienced a google-api-python-client installation problem when you don't already have it installed, and it's listed as a dependency in setup.py:

error: Installed distribution httplib2 0.7.7 conflicts with requirement httplib2>=0.8

Therefore, google-api-python-client has been removed as an explicit dependency. It should always be installed by hand, as we now won't install it automatically.

Installation

pip

Run:

$ sudo pip install gdrivefs

Troubleshooting

If your setuptools package is too old, you might see the following [annoying] error:

error: option --single-version-externally-managed not recognized

See What does “error: option --single-version-externally-managed not recognized” indicate?.

Apparently, the solution is to make sure that you have a healthy copy of Distribute and to, then, uninstall setuptools. However, this doesn't seem to [always] work. You might prefer to use the "easy_install" method, below.

Usage

Before you can mount the account, you must authorize GDriveFS to access it. GDriveFS works by producing a URL that you must visit in a browser. Google will ask for your log-in information and authorization, and then give you an authorization code. You then pass this code back to the GDriveFS utility along with a file-path of where you want it to store the authorization information ("auth storage file"). Then, you can mount it whenever you'd like.

Since this is FUSE, you must be running as root to mount.

  1. To get the authorization URL:

    $ gdfstool auth -u
    To authorize FUSE to use your Google Drive account, visit the following URL to produce an authorization code:
    
    https://accounts.google.com/o/oauth2/auth?scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fdrive+https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fdrive.file&redirect_uri=urn%3Aietf%3Awg%3Aoauth%3A2.0%3Aoob&response_type=code&client_id=626378760250.apps.googleusercontent.com&access_type=offline
    
  2. To set the authorization-code, you must also provide the auth-storage file that you would like to save it as. The name and location of this file is arbitrary:

    $ gdfstool auth -a /var/cache/gdfs/credcache "4/WUsOa-Sm2RhgQtf9_NFAMMbRC.cj4LQYdXfshQV0ieZDAqA-C7ecwI"
    Authorization code recorded.
    
  3. There are three ways to mount the account:

    • Via script (either using the main script "gdfstool mount" or the helper scripts "gdfs"/"mount.gdfs"):
    $ gdfs -o allow_other /var/cache/gdfs/credcache /mnt/gdrivefs
    
    • Via /etc/fstab:
    /var/cache/gdfs/credcache /mnt/gdrivefs gdfs allow_other 0 0
    
    • Directly via gdfstool:
    $ gdfstool mount /var/cache/gdfs/credcache /mnt/gdrivefs
    

Options

Any of the configuration values in the conf.Conf module can be overwritten as "-o" options. You may pass the full array of FUSE options this way, as well.

Format Management

Google Drive will store Google Document files without a standard format. If you wish to download them, you have to select which format you'd like to download it as. One of the more exciting features of this FUSE implementation is the flexibility in choosing which format to download on the fly. See the section below labeled "Displaceables".

If a mime-type isn't provided when requesting a file that requires a mime-type in order to download, GDFS will make a guess based on whether the extension in the filename (if one exists) can be mapped to a mime-type that is available among the export-types provided by GD for that specific file.

The following is an example directory-listing. Notice the following features:

  • Manages duplicates by appending index numbers (e.g. " (2)").
  • Mtimes, permissions, and ownership are correct.
  • Sizes are zero for file-types that Google hosts free of charge. These are always the files that don't have a strict, default format (the length is unknown).
  • Hidden files are prefixed with ".", thus hiding them from normal listings.
  • "Trashed" files are excluded from listings.
  • Any file that will require a mime-type in order to be downloaded has a "#" as the last character of its filename.
-rw-rw-rw- 1 root root       0 Feb 17 07:52 20130217-145200
-rw-rw-rw- 1 root root       0 Feb 17 08:04 20130217-150358
-rw-rw-rw- 1 root root  358356 Feb 15 15:06 American-Pika-with-Food.jpg
-rw-rw-rw- 1 root root    1000 Oct 25 03:53 Dear Biola.docx#
-rw-rw-rw- 1 root root    1000 Oct 25 02:47 Dear Biola.docx (1)#
-rw-rw-rw- 1 root root    1000 Oct 15 14:29 Reflection.docx#
-rw-rw-rw- 1 root root 1536036 Nov 28 22:37 lotterynumbers01.png
drwxrwxrwx 2 root root    4096 Oct  4 06:08 Scratchpad#
drwxrwxrwx 2 root root    4096 Dec  1 19:21 testdir_1421#
-rw-rw-rw- 1 root root       5 Dec  2 08:50 testfile_0350
-rw-rw-rw- 1 root root       0 Dec  2 21:17 .testfile_0417.swp
-rw-rw-rw- 1 root root       0 Dec  3 00:38 testfile_1937
-rw-rw-rw- 1 root root       0 Dec  2 23:13 testfile_hidden_1812
-rw-rw-rw- 1 root root    1000 Oct  4 02:13 Untitled document#

Displaceables

Google Documents stores all of its data on Google Drive. Google will store these files in an agnostic file entry whose format will not be determined until you download it in a specific format. Because the file is not stored in a particular format, it doesn't have a size. Because it doesn't have a size, the OS will not issue reads for more than (0) bytes.

To get around this, a read of these types of files will only return exactly 1000 bytes of JSON-encoded "stub data".. Information about the entry, including the file-path that we've stored it to. This example also shows how we've specified a mime-type in order to get a PDF version of a Google Document file.

$ cp Copy\ of\ Dear\ Biola.docx#application+pdf /target

$ cat /tmp/Copy\ of\ Dear\ Biola.docx#application+pdf 

where something like the following will be displayed:

{"ImageMediaMetadata": null, 
 "Length": 58484, 
 "FilePath": "/tmp/gdrivefs/displaced/Copy of Dear Biola.docx.application+pdf", 
 "EntryId": "1Ih5yvXiNN588EruqrzBv_RBvsKbEvcyquStaJuTZ1mQ", 
 "Title": "Copy of Dear Biola.docx", 
 "RequiresMimeType": true, 
 "Labels": {"restricted": false, 
            "starred": false, 
            "viewed": true, 
            "hidden": false, 
            "trashed": false}, 
 "OriginalMimeType": "application/vnd.google-apps.document", 
 "ExportTypes": ["text/html", 
                 "application/pdf", 
                 "application/vnd.openxmlformats-officedocument.wordprocessingml.document", 
                 "application/vnd.oasis.opendocument.text", 
                 "application/rtf", "text/plain"], 
 "FinalMimeType": "application/pdf"}

From this, you can tell that the file was originally a Google Documents' mimetype, and now its a PDF mime-type. You can also see various flags, as well as the location that the actual, requested file was stored to.

Cache/Change Management

A cache of both the file/folder entries is maintained, as well as a knowledge of file/folder relationships. However, updates are performed every few seconds using GD's "change" functionality.

Permissions

The default UID/GID of files is that of the current user. The default permissions (modes) are the following:

Entry Type Perm
Folder 777
Editable file 666
Non-editable file 444

Whether or not a file is "editable" is [obviously] an attribute reported by Google Drive.

These settings can be overridden via the "-o" comma-separated set of command- line options. See below.

Permission-Related Options

Related Standard FUSE

These options change the behavior at the FUSE level (above GDFS). See "man mount.fuse" for all options.

Option Description
umask=M Prescribe the umask value for -all- entries.
uid=N Change the default UID.
gid=N Change the default GID.
allow_other Allow other users access.
default_permissions Enforce the permission modes (off, by default)

GDFS-Specific

Option Description
default_perm_folder=nnn Default mode for folders.
default_perm_file_noneditable=nnn Default mode for non-editable files.
default_perm_file_editable=nnn Default mode for editable files (see above).

Example:

allow_other,default_permissions,default_perm_folder=770,default_perm_file_noneditable=440,default_perm_file_editable=660

Extended Attributes

Extended attributes allow access to arbitrary, filesystem-specific data. You may access any of the properties that Google Drive provides for a given entry, plus a handful of extra ones.

Listing attributes:

$ getfattr American-Pika-with-Food.jpg

# file: American-Pika-with-Food.jpg
user.extra.download_types
user.extra.is_directory
user.extra.is_visible
user.extra.parents
user.original.alternateLink
user.original.createdDate
user.original.downloadUrl
user.original.editable
user.original.etag
user.original.fileExtension
user.original.fileSize
user.original.iconLink
user.original.id
user.original.imageMediaMetadata
user.original.kind
user.original.labels
user.original.lastModifyingUser
user.original.lastModifyingUserName
user.original.md5Checksum
user.original.mimeType
user.original.modifiedByMeDate
user.original.modifiedDate
user.original.originalFilename
user.original.ownerNames
user.original.owners
user.original.parents
user.original.quotaBytesUsed
user.original.selfLink
user.original.shared
user.original.thumbnailLink
user.original.title
user.original.userPermission
user.original.webContentLink
user.original.writersCanShare

Getting specific attribute:

$ getfattr --only-values -n user.original.id American-Pika-with-Food.jpg 

0B5Ft2OXeDBqSSGFIanJ2Z2c3RWs
$ getfattr --only-values -n user.original.modifiedDate American-Pika-with-Food.jpg

2013-02-15T15:06:09.691Z
$ getfattr --only-values -n user.original.labels American-Pika-with-Food.jpg

K(restricted)=V(False); K(starred)=V(False); K(viewed)=V(False); K(hidden)=V(False); K(trashed)=V(False)

This used to be rendered as JSON, but since the xattr utilities add their own quotes/etc.., it was more difficult to make sense of the values.

Misc Notes

A file will be marked as hidden on Google Drive if it has a prefixing dot. However, Linux/Unix doesn't care about the "hidden" attribute. If you create a file on Google Drive, somewhere else, and want it to truly be hidden via this software, make sure you add the prefixing dot.