Git Product home page Git Product logo

skicka's Introduction

skicka

Utility for working with files and folders stored on Google Drive.

Note: skicka is not an official Google product!

Intro

skicka makes it easy to copy files to and from Google Drive and to work with files stored on Google Drive.

For example, skicka upload ~/Pictures /Pictures copies the entire contents of the local ~/Pictures directory to a folder Pictures in Google Drive. If you then run skicka download /Pictures ~/Pictures2, then the contents of your ~/Pictures2 directory will match the contents of ~/Pictures.

More generally, skicka makes it easy to list the files in Google Drive folders, compute the space used by Drive folders, and copy files between your computer to Google Drive. If you'd like to encrypt your files before uploading them, skicka supports AES-256 encryption.

What skicka is not

skicka is not a general solution for automatically synchronizing files stored in Google Drive across multiple machines. In particular, it doesn't have logic to reconcile concurrent changes to the same file on different machines.

Furthermore, although skicka has been robust in usage so far and has no known data corruption bugs, it should for now be treated as "alpha" software. Bug reports are welcome.

Getting Started

  1. You must have a Go compiler installed.
  2. Download and build skicka: go get github.com/google/skicka
  3. Either copy the skicka executable in $GOPATH/bin to a directory in your PATH, or add $GOPATH/bin to your PATH.
  4. Run skicka init to create a skeleton ~/.skicka.config file. Various options can be set in this file to control skicka's operation; see comments in the file for more information.
  5. Authorize skicka to access your Google Drive files: run skicka ls, and skicka will attempt to open an authorization page in your web browser. Click the "Accept" button to authorize skicka. You only need to perform this step once.
    • Alternatively, you can authorize skicka by running skicka -no-browser-auth ls and skicka will ask you to visit a URL: go to the URL in a browser, log into your Google account (if needed), and give permission for the application to access your Google Drive files. After you click 'accept', copy the code from your browser window to the terminal with the "Enter verification code" prompt from skicka.
  6. After skicka is authorized, it will download and locally cache information about the files you have stored in Google Drive. This may take a while if you have many files on Drive; a progress indicator will try to keep you posted about how this is going. Once this data is stored locally, future runs of skicka will get going much more quickly.
  7. If you're going store encrypted files in Google Drive, create an encryption key: set the environment variable SKICKA_PASSPHRASE to hold your passphrase and run skicka genkey. Copy the lines of text that are printed to the [encryption] section of your ~/.skicka.config file.
  8. Try it out: run skicka ls -l /. A list of the files and folders in the root directory of your Google Drive should be printed.
  9. Join the mailing list!

Usage

For a general overview of skicka's commands, run skicka help.

To copy a local directory hierarchy to Google Drive, use the upload command. As the upload progresses, skicka periodically reports how much data has been uploaded and how much time has elapsed.

% skicka upload ~/Pictures /Pictures
11 / 11 [=====================================================] 100.00 % 
skicka: preparation time 1s, sync time 10s
skicka: updated 0 Drive files, 8 local files
skicka: 4.52 MiB read from disk, 0 B written to disk
skicka: 4.52 MiB uploaded (482 kiB/s), 0 B downloaded (0 B/s)
skicka: 32.76 MiB peak memory used
%

If you'd like to encrypt the files, create an encryption key as described above in "Getting Started" and then use the -encrypt command-line option. skicka looks for your encryption passphrase in the SKICKA_PASSPHRASE environment variable; thus, you might use:

% env SKICKA_PASSPHRASE=mySecretPassphrase skicka upload -encrypt ~/Pictures /EncryptedPictures

To download a directory hierarchy from Google Drive to your local disk, use download. As the download progresses, status is periodically reported:

% skicka download /Pictures/2014 ~/Pictures.copy/2014
10 / 10 [=====================================================] 100.00 % 
skicka: preparation time 1s, sync time 6s
skicka: updated 0 Drive files, 10 local files
skicka: 0 B read from disk, 16.18 MiB written to disk
skicka: 0 B uploaded (0 B/s), 16.18 MiB downloaded (2.33 MiB/s)
skicka: 50.23 MiB peak memory used
%

The ls command can be used to list files and directories in Google Drive. For example, after uploading your ~/Pictures directory, you might run:

% skicka ls /Pictures
2012
2013
2014

To see more detail, ls -l can be used:

% skicka ls -l /Pictures/2013
-rw-r--r--  2.62 MiB  Sun Mar 10 14:41:08 2013  IMG_1127.JPG
-rw-r--r--  2.63 MiB  Sun Mar 10 14:41:09 2013  IMG_1128.JPG
-rw-r--r--  2.32 MiB  Sun Mar 10 14:41:16 2013  IMG_1129.JPG
-rw-r--r--  2.47 MiB  Sun Mar 10 14:43:16 2013  IMG_1130.JPG
[...]

In addition to the filename, we see the file size, the file permissions, and the local modification time that the file on Google Drive is synced to. The file permissions are based on the permissions of the file when it was uploaded to Google Drive.

(For even more detail, ls -ll can be used, which also prints the MD5 checksums of the files on Google Drive.)

The contents of a single file can be downloaded using cat:

% skicka cat /Pictures/2013/IMG_1129.JPG > img.jpg

Google Drive folders can be created with mkdir. (As with the Unix command, the -p option can be specified to indicate that the intermediate directories in the path should be created).

% skicka mkdir /Pictures/2015

The amount of space used by the children of a given Google Drive folder can be reported by du:

% skicka du /Pictures
 81.56 MiB  /Pictures/2012
 92.14 MiB  /Pictures/2013
121.02 MiB  /Pictures/2014
294.72 MiB  /Pictures

You can remove a file with rm; by default, files are moved to the Trash in Google Drive:

% skicka rm /Pictures/2014/embarassing.jpg

If you'd like to delete the file immediately with no chance to recover it, use the -s command-line option to rm. To remove a folder and everything inside it, use -r.

Finally, there is a fsck command that checks the file system on Google Drive for problems and verifies that the local cache of file metadata is in-sync with the files stored on Drive.

FAQs

Can skicka work with Google Drive files that it didn't create itself?

Yes. The only limitations are that regular Google Drive files don't store the Unix permissions or the local modification of the original file when it was uploaded. Therefore, in this case skicka download uses 644 permissions for files it creates and 755 permissions for directories.

skicka ls -l indicates that a file has world-readable permissions on Google Drive; does this mean anyone can access it?

No. Those permissions are only used to set the local file permissions when the file is downloaded with skicka download. The access permissions for the files stored on Drive are handled with Drive's regular mechanisms.

How can I speed up uploads?

There's a fixed per-file overhead for each file uploaded to Google Drive that limits skicka to creating roughly five files a second; if files are relatively small, this overhead will be more of a limit than the time spent transferring the contents of the files.

If the uploaded files don't need to be accessed individually, creating a tar or zip archive of them before uploading may help in this case.

I occasionally see "operation timed out" or "broken pipe" errors when uploading; what's going on?

A variety of transient errors can happen when using RESTful APIs like the Google Drive API. When these errors are encountered, skicka makes a number of attempts to retry the operation before giving up.

It may be that skicka should make more attempts before giving up or that there are better error handling strategies; one trade-off is that if there is a serious error (like the internet connection is lost), then it's useful for the user to know this sooner rather than later.

If you do see these errors, re-run the operation you were performing; any files that weren't transferred the first time should be taken care of with a second run.

Does skicka support rate-limited uploads and downloads?

Yes. By default, skicka doesn't try to limit its bandwidth usage. However, if you add a line bytes-per-second-limit=... to the [upload] or [download] section of your .skicka.config file, you can specify a maximum number of bytes per second to transfer for uploads or downloads, respectively.

If this line isn't present (or has a value of zero), then bandwidth won't be limited.

Can an http proxy be used with skicka?

Yes--just set the HTTP_PROXY environment variable appropriately.

"skicka"?!?

Swedish, "to send".

Implementation notes

How files are stored in Google Drive

When a directory hierarchy is uploaded, Google Drive file is created for each local file and a Google Drive folder is created for each local directory. skicka stores the time the local copy file was last modified in the "modifiedDate" Google Drive File resource. The Unix file permissions of the file or directory are stored in using a custom "Permissions" file property, stored as a string with the octal file permissions.

See the discussion of encryption below for details about how encrypted files are represented.

Synchronization algorithm

When deciding if a local file needs to be uploaded to Google Drive, skicka performs the following checks.

  1. If there is no corresponding file on Drive, the local file will be uploaded.
  2. Otherwise, if there is a corresponding file on Drive and the sizes of the files are different, the local file will be uploaded.
  3. Otherwise, if the local file's modification time is after the modification time of the file the last time it was synced to Drive, then an MD5 checksum of the file contents is computed. If this checksum differs from the checksum of the file stored on Google Drive, the file will be uploaded. (Thus, if touch is run on a file to update its modification time but the file's contents aren't modified, skicka won't unnecessarily re-upload the file.)

Note that skicka trusts that file modification times are meaningful: if a file's contents are modified leaving the file size is unchanged and if the modification time is set to be in the past, then skicka won't compute an MD5 checksum and won't know that the file should be uploaded. To override this behavior, run skicka upload with the -ignore-times flag; if this flag is provided, then the MD5 checksum check in the third step will be applied regardless of the file modification time.

Note also that this algorithm is an algorithm to efficiently mirror the contents of a set of local files on Google Drive; it's not a general bidirectional synchronization algorithm. For example, if a file is modified both on Drive and on the local filesystem, a skicka upload run will clobber the file contents on Drive. In other words, the assumption is that the source directory hierarchy is by definition the canonical one and the destination directory's role is to perfectly reflect the source.

When downloading from Google Drive, skicka follows the same general approach: only files that don't yet exist, have different sizes, or different MD5 checksums from the corresponding local file will be downloaded. The -ignore-times option can also be used to bypass the file modification time check and to force a comparison of file contents to decide whether to download.

Encryption

If the -encrypt flag is provided to the upload command, skicka will encrypt the contents of each file before uploading it to Google Drive. Conversely, the download and cat commands transparently decrypt encrypted files when downloading them (if the encryption key and passphrase are available!)

Encryption requires both an encryption key and a passphrase; your passphrase should be stored in the SKICKA_PASSPHRASE environment variable. To generate an encryption key, run skicka genkey. For example:

% env SKICKA_PASSPHRASE=mySecretPassphrase skicka genkey
[...]

skicka will generate a few lines of output that are your encrypted encryption key; to save your key, edit your ~/.skicka.config file and add the printed text to the [encryption] section of the file. You can now upload and encrypt files:

% env SKICKA_PASSPHRASE=mySecretPassphrase skicka upload -encrypt ~/backups /backups

If you lose your encryption key or forget your passphrase, your encrypted data is lost forever. If you use encryption, please be very careful with this information.

skicka only encrypts file contents: it doesn't encrypt filenames or hide file sizes, for example. If this is problematic for your usage, you should probably use tar or zip to put the files you want to encrypt into a single file before uploading it.

Key generation and storage

When skicka genkey is executed, an encryption key is generated as follows:

  1. skicka generates a random 32-byte salt using Go's rand.Reader, which returns cryptographically secure pseudo-random numbers. The hex-encoded salt is printed out, and should be recorded in the salt field of the [encryption] section of the config file.
  2. The user's passphrase, read from the SKICKA_PASSPHRASE environment variable, is run through the PBKDF2 key derivation function, using 65536 iterations and the SHA-256 hash function to derive a 64-byte hash.
  3. The first 32 bytes of the hash are hex encoded and printed out; they should be copied to the passphrase-hash field of the [encryption] section of the config file. These bytes are later used only to validate that the user has provided the correct passphrase on subsequent runs of skicka.
  4. A random 32-byte encryption key is generated (again with rand.Reader). This is the key that will actually be used for encryption and decryption of file contents.
  5. A random 16-byte initialization vector is generated with rand.Reader. It is hex encoded and printed out, and should be copied to the encrypted-key-iv configuration file field.
  6. The encryption key from #4 is encrypted using the initialization vector from #5, using the second 32 bytes of the hash computed in #2 as the encryption key. The result should be copied to the encrypted-key field of the config file.

Upon subsequent runs of skicka, the salt is loaded from the config file so that PBKDF2 can be used as in #2 above to hash the user's passphrase. If the first 32 bytes of the passphrase hash match the stored bytes, then the second 32 bytes of the hash and the stored IV are used to decrypt the encrypted encryption key.

Given the encryption key, when a file is to be encrypted before being uploaded to Google Drive, skicka uses the key along with a fresh 16-byte initialization vector for each file to encrypt the file using AES-256. The initialization vector is prepended to the file contents before upload. (Thus, encrypted files are 16 bytes larger on Google Drive than they are locally.)

The initialization vector is also stored hex-encoded as a Google Drive file Property with the name "IV". We store the initialization vector redundantly so that if one downloads the encrypted file contents, it's possible to decrypt the file using the file contents (and the key!) alone. Conversely, also having the IV available in a property makes it possible to encrypt the contents of a local version of a file without needing to download any of the contents of the corresponding file from Google Drive.

skicka's People

Contributors

agoode avatar austindizzy avatar bgrainger avatar clonemeagain avatar danmarg avatar gusennan avatar kojinakamaru avatar mmp avatar necrodome avatar perry369 avatar tsekityam avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

skicka's Issues

Add 'rm' functionality

It would be nice to be able to do 'rm'. This should probably support '-r' to recursively remove directory hierarchies and should have an option to either put the removed stuff in the Google Drive trash or to just fully delete things immediately.

Files >1.6 GB fail to upload

When I upload files >1.6GB, the upload runs for a long time, then fails with error *googleapi.Error googleapi: Error 401: Invalid Credentials, authError. The file exists in Drive as a 0-byte file.

This sounds like a server problem, but perhaps there is a workaround possible.

Problem uploading...

I tried to get & compile the latest skicka using the recommended command:
go get github.com/google/skicka

however when I tried to upload a file with specified path such as this:
skicka upload ./funny.mkv /Mov_UL
I have made sure that the Mov_UL folder already existed before giving the command. However, the upload process is a success. But when I check with the web browser, it doesn't upload as expected. I got a file named "Mov_UL" (which was the specified folder name) and when I tried to open it, it gave such error message:
error_msg) I tried another command such as:
skicka upload ./funny.mkv /Mov_UL/ (added a tailed slash) but still not working correctly.

Please help. skicka is quite a command with very friendly interface. I want to use it constantly!

Thanks

Would/does the drive API support delta syncing for large files?

May as well apply the "question" label to this. It doesn't pay to ask for a delta feature, if Google's API and/or backing store doesn't make this easy, or possible.
Transfer requests can be resume-able and, I believe, transfers can be chunked. Is there be a way to calculate hashes on the server-side chunks, to compare to local chunks, to do something like rsync's delta algorithm? This would have some server-side processing overhead, but might reduce Google's transfer load, when dealing with large files.

BTW, thanks for this nice utility. It's my first Go -compiled program. -interesting. I compiled on my PC-BSD machine at work. I was pleasantly surprised when it just worked, when I just scp'ed the ELF executable to my home PC-BSD machine. -even when the "file" utility reported that it was dynamically linked (I hadn't installed the golang port, at home).

Also, I like the thoughtful encryption implementation.

Rate-limit uploads and downloads

It would be good to be able to limit the bandwidth used for uploads and downloads. The Drive SDK doesn't provide this functionality directly, so this will presumably be a matter of doing the http PUT for file upload manually and then rate-limiting the data sent along to the PUT.

improve progress bar accuracy

Currently it keys off of the number of files and directories to be uploaded/downloaded, rather than their sizes. Thus, if one's uploading a single (large) file, for example, it's fairly useless. It'd be better to track the amount of data transferred vs the total amount to be transferred.

cache remote file structure to improve startup time

If there are many files/folders in Google Drive, it takes a long time to walk through the folders in Drive and get the *drive.Files for all of the files. The best option is probably to cache that information locally and then update it at startup time using the Drive notification stream.

main.syncFileUp: invalid memory address or nil pointer dereference

It is 100% reproducible for this particular directory. Oddly it leaves me with duplicate files afterwards, I'm not sure if that is a symptom or cause. I'll look up how to do a debug build and get a better call stack if that would be useful?

dan@georgeiii:~$ skicka upload /srv/samba/photos/Pictures/2011/ /Pictures/2011/
skicka: Getting list of files to upload... Done. Starting upload.
342.02 MB / 4.43 GB [===>-------------------------------------] 7.54 % 40h38m36spanic: runtime error: invalid memory address or nil pointer dereference
signal 0xb code=0x1 addr=0x10 pc=0x40bdc1]

goroutine 12 [running]:
runtime.panic(0x6d57a0, 0xa6cde8)
/usr/lib/go/src/pkg/runtime/panic.c:266 +0xb6
main.syncFileUp(0xc2104a3040, 0x37, 0xc21048f990, 0x26, 0x7fad8bef9540, ...)
/home/dan/go/src/github.com/google/skicka/skicka.go:1387 +0xe01
main.func·002()
/home/dan/go/src/github.com/google/skicka/skicka.go:1508 +0x1f8
created by main.syncHierarchyUp
/home/dan/go/src/github.com/google/skicka/skicka.go:1520 +0xbbd

goroutine 1 [chan send]:
main.syncHierarchyUp(0x7fff434b433b, 0x1f, 0x7fff434b435c, 0xe, 0xc2100790c0, ...)
/home/dan/go/src/github.com/google/skicka/skicka.go:1526 +0xcbc
main.upload()
/home/dan/go/src/github.com/google/skicka/skicka.go:2524 +0x516
main.main()
/home/dan/go/src/github.com/google/skicka/skicka.go:2646 +0xa5b

goroutine 3 [syscall]:
runtime.goexit()
/usr/lib/go/src/pkg/runtime/proc.c:1394
goroutine 7 [sleep]:
time.Sleep(0x7735940)
/usr/lib/go/src/pkg/runtime/time.goc:31 +0x31
main.func·001()
/home/dan/go/src/github.com/google/skicka/skicka.go:182 +0xc1
created by main.launchBandwidthTask
/home/dan/go/src/github.com/google/skicka/skicka.go:184 +0x71

goroutine 5 [IO wait]:
net.runtime_pollWait(0x7fad8befa880, 0x72, 0x0)
/usr/lib/go/src/pkg/runtime/netpoll.goc:116 +0x6a
net.(_pollDesc).Wait(0xc210052df0, 0x72, 0x7fad8bef90e8, 0xb)
/usr/lib/go/src/pkg/net/fd_poll_runtime.go:81 +0x34
net.(_pollDesc).WaitRead(0xc210052df0, 0xb, 0x7fad8bef90e8)
/usr/lib/go/src/pkg/net/fd_poll_runtime.go:86 +0x30
net.(_netFD).Read(0xc210052d90, 0xc2101ee000, 0x1000, 0x1000, 0x0, ...)
/usr/lib/go/src/pkg/net/fd_unix.go:204 +0x2a0
net.(_conn).Read(0xc2100005f8, 0xc2101ee000, 0x1000, 0x1000, 0x422d9f, ...)
/usr/lib/go/src/pkg/net/net.go:122 +0xc5
crypto/tls.(_block).readFromUntil(0xc210079540, 0x7fad8befa9d8, 0xc2100005f8, 0x5, 0xc2100005f8, ...)
/usr/lib/go/src/pkg/crypto/tls/conn.go:459 +0xb6
crypto/tls.(_Conn).readRecord(0xc21005b500, 0x17, 0x0, 0x8)
/usr/lib/go/src/pkg/crypto/tls/conn.go:539 +0x107
crypto/tls.(_Conn).Read(0xc21005b500, 0xc2101b9000, 0x1000, 0x1000, 0x0, ...)
/usr/lib/go/src/pkg/crypto/tls/conn.go:897 +0x135
bufio.(_Reader).fill(0xc2101db660)
/usr/lib/go/src/pkg/bufio/bufio.go:91 +0x110
bufio.(_Reader).Peek(0xc2101db660, 0x1, 0x0, 0x0, 0x0, ...)
/usr/lib/go/src/pkg/bufio/bufio.go:119 +0xcb
net/http.(_persistConn).readLoop(0xc210061600)
/usr/lib/go/src/pkg/net/http/transport.go:687 +0xb7
created by net/http.(*Transport).dialConn
/usr/lib/go/src/pkg/net/http/transport.go:528 +0x607

goroutine 6 [sleep]:
time.Sleep(0x5f5e100)
/usr/lib/go/src/pkg/runtime/time.goc:31 +0x31
main.RateLimitedReader.Read(0x7fad881a0c38, 0xc2102a1160, 0xc2101951d8, 0xe28, 0xe28, ...)
/home/dan/go/src/github.com/google/skicka/skicka.go:214 +0x1bc
main.(_RateLimitedReader).Read(0xc210784b10, 0xc2101951d8, 0xe28, 0xe28, 0x1d8, ...)
/home/dan/go/src/github.com/google/skicka/skicka.go:1 +0xb3
io.(_multiReader).Read(0xc2102a1820, 0xc2101951d8, 0xe28, 0xe28, 0x1d8, ...)
/usr/lib/go/src/pkg/io/multi.go:13 +0xa2
io/ioutil.(_nopCloser).Read(0xc210784b50, 0xc2101951d8, 0xe28, 0xe28, 0x1d8, ...)
/usr/lib/go/src/pkg/io/ioutil/blackhole.go:1 +0x68
io.(_LimitedReader).Read(0xc2102a1f80, 0xc2101951d8, 0xe28, 0xe28, 0x1d8, ...)
/usr/lib/go/src/pkg/io/io.go:398 +0xbb
bufio.(_Writer).ReadFrom(0xc210238500, 0x7fad8bf04350, 0xc2102a1f80, 0x6063072, 0x0, ...)
/usr/lib/go/src/pkg/bufio/bufio.go:622 +0x15a
io.Copy(0x7fad8bf042b0, 0xc210238500, 0x7fad8bf04350, 0xc2102a1f80, 0x0, ...)
/usr/lib/go/src/pkg/io/io.go:348 +0x124
net/http.(_transferWriter).WriteBody(0xc210adc460, 0x7fad8bf042b0, 0xc210238500, 0x0, 0x0)
/usr/lib/go/src/pkg/net/http/transfer.go:196 +0x57c
net/http.(_Request).write(0xc21067a5b0, 0x7fad8bf042b0, 0xc210238500, 0x0, 0xc21088cc60, ...)
/usr/lib/go/src/pkg/net/http/request.go:400 +0x7e4
net/http.(_persistConn).writeLoop(0xc210061600)
/usr/lib/go/src/pkg/net/http/transport.go:797 +0x185
created by net/http.(*Transport).dialConn
/usr/lib/go/src/pkg/net/http/transport.go:529 +0x61e

goroutine 9 [sleep]:
time.Sleep(0xbebc200)
/usr/lib/go/src/pkg/runtime/time.goc:31 +0x31
github.com/cheggaaa/pb.(_ProgressBar).writer(0xc210cc6a50)
/home/dan/go/src/github.com/cheggaaa/pb/pb.go:332 +0x48
created by github.com/cheggaaa/pb.(_ProgressBar).Start
/home/dan/go/src/github.com/cheggaaa/pb/pb.go:101 +0x70

goroutine 10 [select]:
net/http.(_persistConn).roundTrip(0xc210061600, 0xc210784b90, 0xc210061600, 0x0, 0x0)
/usr/lib/go/src/pkg/net/http/transport.go:879 +0x6d6
net/http.(_Transport).RoundTrip(0xc210061200, 0xc21067a5b0, 0xd, 0x0, 0x0)
/usr/lib/go/src/pkg/net/http/transport.go:187 +0x391
code.google.com/p/goauth2/oauth.(*Transport).RoundTrip(0xc21001e4e0, 0xc21067a5b0, 0xc210784b10, 0x1550f6cd, 0xc21067a4e0)
/home/dan/go/src/code.google.com/p/goauth2/oauth/oauth.go:296 +0x10f
main.uploadFileContents(0xc210c3bdc0, 0x7fad881a0c38, 0xc2102a1160, 0x1550f6cd, 0x0, ...)
/home/dan/go/src/github.com/google/skicka/skicka.go:1040 +0x115
main.syncFileUp(0xc21048e540, 0x37, 0xc21048f060, 0x26, 0x7fad8bef9540, ...)
/home/dan/go/src/github.com/google/skicka/skicka.go:1376 +0xc2f
main.func·002()
/home/dan/go/src/github.com/google/skicka/skicka.go:1508 +0x1f8
created by main.syncHierarchyUp
/home/dan/go/src/github.com/google/skicka/skicka.go:1520 +0xbbd

goroutine 11 [select]:
net/http.(_persistConn).roundTrip(0xc210c92600, 0xc210778100, 0xc210c92600, 0x0, 0x0)
/usr/lib/go/src/pkg/net/http/transport.go:879 +0x6d6
net/http.(_Transport).RoundTrip(0xc210061200, 0xc21067aa90, 0xd, 0x0, 0x0)
/usr/lib/go/src/pkg/net/http/transport.go:187 +0x391
code.google.com/p/goauth2/oauth.(*Transport).RoundTrip(0xc21001e4e0, 0xc21067aa90, 0xc210780630, 0x61600c9, 0xc21067a9c0)
/home/dan/go/src/code.google.com/p/goauth2/oauth/oauth.go:296 +0x10f
main.uploadFileContents(0xc210c3c340, 0x7fad881a0c38, 0xc21031e260, 0x61600c9, 0x0, ...)
/home/dan/go/src/github.com/google/skicka/skicka.go:1040 +0x115
main.syncFileUp(0xc21049ff40, 0x37, 0xc21048f930, 0x26, 0x7fad8bef9540, ...)
/home/dan/go/src/github.com/google/skicka/skicka.go:1376 +0xc2f
main.func·002()
/home/dan/go/src/github.com/google/skicka/skicka.go:1508 +0x1f8
created by main.syncHierarchyUp
/home/dan/go/src/github.com/google/skicka/skicka.go:1520 +0xbbd

goroutine 13 [select]:
net/http.(_persistConn).roundTrip(0xc210c92680, 0xc210780e40, 0xc210c92680, 0x0, 0x0)
/usr/lib/go/src/pkg/net/http/transport.go:879 +0x6d6
net/http.(_Transport).RoundTrip(0xc210061200, 0xc21067a750, 0xd, 0x0, 0x0)
/usr/lib/go/src/pkg/net/http/transport.go:187 +0x391
code.google.com/p/goauth2/oauth.(*Transport).RoundTrip(0xc21001e4e0, 0xc21067a750, 0xc210780dc0, 0x9fe9cad, 0xc21067a680)
/home/dan/go/src/code.google.com/p/goauth2/oauth/oauth.go:296 +0x10f
main.uploadFileContents(0xc210c3c8c0, 0x7fad881a0c38, 0xc2100a2740, 0x9fe9cad, 0x0, ...)
/home/dan/go/src/github.com/google/skicka/skicka.go:1040 +0x115
main.syncFileUp(0xc2105f8340, 0x37, 0xc2104adab0, 0x26, 0x7fad8bef9540, ...)
/home/dan/go/src/github.com/google/skicka/skicka.go:1376 +0xc2f
main.func·002()
/home/dan/go/src/github.com/google/skicka/skicka.go:1508 +0x1f8
created by main.syncHierarchyUp
/home/dan/go/src/github.com/google/skicka/skicka.go:1520 +0xbbd

goroutine 19 [runnable]:
net/http.(_persistConn).readLoop(0xc210c92780)
/usr/lib/go/src/pkg/net/http/transport.go:778 +0x68f
created by net/http.(_Transport).dialConn
/usr/lib/go/src/pkg/net/http/transport.go:528 +0x607

goroutine 21 [IO wait]:
net.runtime_pollWait(0x7fad8befa688, 0x72, 0x0)
/usr/lib/go/src/pkg/runtime/netpoll.goc:116 +0x6a
net.(_pollDesc).Wait(0xc210bcbfb0, 0x72, 0x7fad8bef90e8, 0xb)
/usr/lib/go/src/pkg/net/fd_poll_runtime.go:81 +0x34
net.(_pollDesc).WaitRead(0xc210bcbfb0, 0xb, 0x7fad8bef90e8)
/usr/lib/go/src/pkg/net/fd_poll_runtime.go:86 +0x30
net.(_netFD).Read(0xc210bcbf50, 0xc2105f9000, 0x1000, 0x1000, 0x0, ...)
/usr/lib/go/src/pkg/net/fd_unix.go:204 +0x2a0
net.(_conn).Read(0xc210846820, 0xc2105f9000, 0x1000, 0x1000, 0x422d9f, ...)
/usr/lib/go/src/pkg/net/net.go:122 +0xc5
crypto/tls.(_block).readFromUntil(0xc2108c27b0, 0x7fad8befa9d8, 0xc210846820, 0x5, 0xc210846820, ...)
/usr/lib/go/src/pkg/crypto/tls/conn.go:459 +0xb6
crypto/tls.(_Conn).readRecord(0xc2101bbc80, 0x17, 0x0, 0x8)
/usr/lib/go/src/pkg/crypto/tls/conn.go:539 +0x107
crypto/tls.(_Conn).Read(0xc2101bbc80, 0xc210853000, 0x1000, 0x1000, 0x0, ...)
/usr/lib/go/src/pkg/crypto/tls/conn.go:897 +0x135
bufio.(_Reader).fill(0xc210b5a720)
/usr/lib/go/src/pkg/bufio/bufio.go:91 +0x110
bufio.(_Reader).Peek(0xc210b5a720, 0x1, 0x0, 0x0, 0x0, ...)
/usr/lib/go/src/pkg/bufio/bufio.go:119 +0xcb
net/http.(_persistConn).readLoop(0xc210c92680)
/usr/lib/go/src/pkg/net/http/transport.go:687 +0xb7
created by net/http.(*Transport).dialConn
/usr/lib/go/src/pkg/net/http/transport.go:528 +0x607

goroutine 17 [IO wait]:
net.runtime_pollWait(0x7fad8befa7d8, 0x72, 0x0)
/usr/lib/go/src/pkg/runtime/netpoll.goc:116 +0x6a
net.(_pollDesc).Wait(0xc210bcbed0, 0x72, 0x7fad8bef90e8, 0xb)
/usr/lib/go/src/pkg/net/fd_poll_runtime.go:81 +0x34
net.(_pollDesc).WaitRead(0xc210bcbed0, 0xb, 0x7fad8bef90e8)
/usr/lib/go/src/pkg/net/fd_poll_runtime.go:86 +0x30
net.(_netFD).Read(0xc210bcbe70, 0xc2109dbc00, 0x400, 0x400, 0x0, ...)
/usr/lib/go/src/pkg/net/fd_unix.go:204 +0x2a0
net.(_conn).Read(0xc2108467c0, 0xc2109dbc00, 0x400, 0x400, 0x422d9f, ...)
/usr/lib/go/src/pkg/net/net.go:122 +0xc5
crypto/tls.(_block).readFromUntil(0xc210928ba0, 0x7fad8befa9d8, 0xc2108467c0, 0x5, 0xc2108467c0, ...)
/usr/lib/go/src/pkg/crypto/tls/conn.go:459 +0xb6
crypto/tls.(_Conn).readRecord(0xc2101bba00, 0x17, 0x0, 0x8)
/usr/lib/go/src/pkg/crypto/tls/conn.go:539 +0x107
crypto/tls.(_Conn).Read(0xc2101bba00, 0xc2103a5000, 0x1000, 0x1000, 0x0, ...)
/usr/lib/go/src/pkg/crypto/tls/conn.go:897 +0x135
bufio.(_Reader).fill(0xc210b5a4e0)
/usr/lib/go/src/pkg/bufio/bufio.go:91 +0x110
bufio.(_Reader).Peek(0xc210b5a4e0, 0x1, 0x0, 0x0, 0x0, ...)
/usr/lib/go/src/pkg/bufio/bufio.go:119 +0xcb
net/http.(_persistConn).readLoop(0xc210c92600)
/usr/lib/go/src/pkg/net/http/transport.go:687 +0xb7
created by net/http.(*Transport).dialConn
/usr/lib/go/src/pkg/net/http/transport.go:528 +0x607

goroutine 18 [sleep]:
time.Sleep(0x5f5e100)
/usr/lib/go/src/pkg/runtime/time.goc:31 +0x31
main.RateLimitedReader.Read(0x7fad881a0c38, 0xc21031e260, 0xc21043290f, 0x6f1, 0x6f1, ...)
/home/dan/go/src/github.com/google/skicka/skicka.go:214 +0x1bc
main.(_RateLimitedReader).Read(0xc210780630, 0xc21043290f, 0x6f1, 0x6f1, 0x90f, ...)
/home/dan/go/src/github.com/google/skicka/skicka.go:1 +0xb3
io.(_multiReader).Read(0xc2105741a0, 0xc21043290f, 0x6f1, 0x6f1, 0x90f, ...)
/usr/lib/go/src/pkg/io/multi.go:13 +0xa2
io/ioutil.(_nopCloser).Read(0xc2107780c0, 0xc21043290f, 0x6f1, 0x6f1, 0x90f, ...)
/usr/lib/go/src/pkg/io/ioutil/blackhole.go:1 +0x68
io.(_LimitedReader).Read(0xc210574460, 0xc21043290f, 0x6f1, 0x6f1, 0x90f, ...)
/usr/lib/go/src/pkg/io/io.go:398 +0xbb
bufio.(_Writer).ReadFrom(0xc210915bc0, 0x7fad8bf04350, 0xc210574460, 0x4dcb7a9, 0x0, ...)
/usr/lib/go/src/pkg/bufio/bufio.go:622 +0x15a
io.Copy(0x7fad8bf042b0, 0xc210915bc0, 0x7fad8bf04350, 0xc210574460, 0x0, ...)
/usr/lib/go/src/pkg/io/io.go:348 +0x124
net/http.(_transferWriter).WriteBody(0xc210adcb60, 0x7fad8bf042b0, 0xc210915bc0, 0x0, 0x0)
/usr/lib/go/src/pkg/net/http/transfer.go:196 +0x57c
net/http.(_Request).write(0xc21067aa90, 0x7fad8bf042b0, 0xc210915bc0, 0x0, 0xc2107f8180, ...)
/usr/lib/go/src/pkg/net/http/request.go:400 +0x7e4
net/http.(_persistConn).writeLoop(0xc210c92600)
/usr/lib/go/src/pkg/net/http/transport.go:797 +0x185
created by net/http.(*Transport).dialConn
/usr/lib/go/src/pkg/net/http/transport.go:529 +0x61e

goroutine 20 [select]:
net/http.(_persistConn).writeLoop(0xc210c92780)
/usr/lib/go/src/pkg/net/http/transport.go:791 +0x271
created by net/http.(_Transport).dialConn
/usr/lib/go/src/pkg/net/http/transport.go:529 +0x61e

goroutine 22 [sleep]:
time.Sleep(0x5f5e100)
/usr/lib/go/src/pkg/runtime/time.goc:31 +0x31
main.RateLimitedReader.Read(0x7fad881a0c38, 0xc2100a2740, 0xc21069843a, 0xbc6, 0xbc6, ...)
/home/dan/go/src/github.com/google/skicka/skicka.go:214 +0x1bc
main.(_RateLimitedReader).Read(0xc210780dc0, 0xc21069843a, 0xbc6, 0xbc6, 0x43a, ...)
/home/dan/go/src/github.com/google/skicka/skicka.go:1 +0xb3
io.(_multiReader).Read(0xc2100ad640, 0xc21069843a, 0xbc6, 0xbc6, 0x43a, ...)
/usr/lib/go/src/pkg/io/multi.go:13 +0xa2
io/ioutil.(_nopCloser).Read(0xc210780e00, 0xc21069843a, 0xbc6, 0xbc6, 0x43a, ...)
/usr/lib/go/src/pkg/net/fd_unix.go:204 +0x2a0
net.(_conn).Read(0xc2108397b0, 0xc210cc5000, 0x1000, 0x1000, 0x10702660, ...)
/usr/lib/go/src/pkg/net/net.go:122 +0xc5
crypto/tls.(_block).readFromUntil(0xc21060f300, 0x7fad8befa9d8, 0xc2108397b0, 0x5, 0xc2108397b0, ...)
/usr/lib/go/src/pkg/crypto/tls/conn.go:459 +0xb6
crypto/tls.(_Conn).readRecord(0xc2101bb780, 0x17, 0x0, 0x8)
/usr/lib/go/src/pkg/crypto/tls/conn.go:539 +0x107
crypto/tls.(_Conn).Read(0xc2101bb780, 0xc2108fd000, 0x1000, 0x1000, 0x0, ...)
/usr/lib/go/src/pkg/crypto/tls/conn.go:897 +0x135
bufio.(_Reader).fill(0xc210702660)
/usr/lib/go/src/pkg/bufio/bufio.go:91 +0x110
bufio.(_Reader).Peek(0xc210702660, 0x1, 0x0, 0x0, 0x0, ...)
/usr/lib/go/src/pkg/bufio/bufio.go:119 +0xcb
net/http.(_persistConn).readLoop(0xc210b10f00)
/usr/lib/go/src/pkg/net/http/transport.go:687 +0xb7
created by net/http.(*Transport).dialConn
/usr/lib/go/src/pkg/net/http/transport.go:528 +0x607

goroutine 124 [select]:
net/http.(_persistConn).writeLoop(0xc210b10f00)
/usr/lib/go/src/pkg/net/http/transport.go:791 +0x271
created by net/http.(_Transport).dialConn
/usr/lib/go/src/pkg/net/http/transport.go:529 +0x61e

dan@georgeiii:~$ skicka upload /srv/samba/photos/Pictures/2011/ /Pictures/2011/
skicka: Getting list of files to upload... skicka: /Pictures/2011/2011-01-11/MVI_6685.MOV: duplicate file found on Google Drive

Add option to delete files on upload/download

Currently, if we upload a local hierarchy to Drive, delete a file locally, and then re-upload, the copy of the file on Drive isn't deleted. We should add an option to delete the copy on Drive (and to do the converse when downloading, if the file was deleted on Drive).

confusing error with 'rm' of multiple targets

% skicka rm -r /tmp /tmp2 /tmp3 /tmp4
rm syntax error: drive path cannot be empty.
Usage: rm [-r, -s] drive path
exit status 1
%

(We should just remove all of them, like normal 'rm' does...)

confusing error message if upload directory doesn't exist

If directory /foo exists and is empty and one runs skicka upload foo.txt /foo/bar/not_there, then the upload fails with the unclear error "skicka: /foo/bar: get parent directory: file does not exist". It would be nice to have a more clear message in that case.

Improve performance of uploading small files?

With small files, we're currently limited by the combination of a few hundred ms of latency for the Drive API calls cross the rate-limit of about ~10 API calls per second before we start getting 401 rate-limit errors. The upshot of this is that with many small files, we end up with kB/s of upload bandwidth, which is unfortunate.

(It's not obvious what the best solution is to this.)

Panic with skicka init

$ ./skicka init
panic: runtime error: invalid memory address or nil pointer dereference
[signal 0xb code=0x1 addr=0x40 pc=0x401161]

goroutine 1 [running]:
runtime.panic(0x6b8de0, 0xa3b9a8)
    /usr/lib/golang/src/pkg/runtime/panic.c:266 +0xb6
main.tildeExpand(0x751210, 0x10, 0x751200, 0x73a810, 0x17, ...)
    /home/agoode/gocode/src/github.com/google/skicka/skicka.go:138 +0xc1
main.main()
    /home/agoode/gocode/src/github.com/google/skicka/skicka.go:2267 +0x218

fully wrap *drive.File in the gdrive interface

It would be a bit cleaner for gdrive to provide its own representation for a file on Drive (maybe e.g. including the entire Drive pathname), and no longer return / take *drive.Files through it interface. Then calling code in skicka could be completely independent of the details of the official Drive API.

better error checking for uploading on top of a file (trying to treat it as a directory)

If I upload a file:

% skicka upload foo /foo

And then do this silly thing:

% skicka upload foo /foo/foo

(Trying to treat /foo as a folder rather than a file), skicka goes into exponential backoff mode, retrying a bunch of files before failing: "2014/12/02 10:12:29 exponential backoff: slept for error googleapi: Error 400: Parent is not a folder")

We should notice earlier on if the target "folder" is actually a regular file on Drive and issue a reasonable error message in this case.

md5 is sometimes unnecessarily computed on uploads

When uploading, we end up computing the MD5 of local files even in cases where it's totally obvious that it won't match (e.g. file sizes are different).

This is a little messy to fix, since the code mixes together "modification times don't match", which may or may not indicate that the contents don't match, and does require a local MD5, with "file sizes don't match", which definitely does indicate that the contents don't match. In general, all of the logic around "should we upload this file or not" is probably more complex than it should be...

skicka: error creating Google Drive client: rename /tmp/skicka.metadata668194580 /usr/home/me/.skicka.metadata.cache: cross-device link

That's one thing a recent update broke, for me. My OS (PC-BSD) is on a ZFS mirror, and I think /tmp and /usr/home/ might be on different data sets. FreeBSD might not allow cross-device links, by default.
See: http://golang.org/pkg/os/#Rename
"OS-specific restrictions might apply."

Maybe the temp file could be made in the home dir. I see you create and use a userHomeDir() function in skicka.go. If that were included in gdrive.go, maybe you could do:

f, err := ioutil.TempFile(userHomrDir(), "skicka.metadata")

I don't know if it makes sense to include a skicka.go function in gdrive.go, or if a separate utilities library file is in order, to serve both.

I realize this might not affect many others. But this is a little like download utilities: They often keep the temporary partial download files in the same directory, as the completed download; not in the system temp dir.

The temp file is worthless if something goes wrong (unless, maybe, for debugging), and perhaps ought to be deleted on error, anyway.
"It is the caller's responsibility to remove the file when no longer needed." (http://golang.org/pkg/io/ioutil/#TempFile)
I guess that is moot if the rename works, but . . .

One odd thing is that I can do that same rename (mv) from my bash command line. So I don't know if golang's os.rename is using the same library, or if the OS packaged console apps are afforded more permission, or . . .

Improve handling of TCP timeouts and connection resets

With long uploads/downloads, we generally hit a few timeouts and resets, especially with large files. Though we retry (with exponential backoff), we still sometimes fail on a few files. While a subsequent run of skicka generally takes care of this, this is still not a great user experience.

Files are completely buffered in memory

If I am uploading large files, the files are buffered in memory completely. There should be a way to stream to the server. This might need to be fixed in the google API library itself.

multithread google drive folder creation?

It can be slow to get the folders all made, especially with large numbers of folders. We just need to make sure that parent folders are created before their children...

duplicate file found on Google Drive

skicka reports an following error if the folder on Google Drive has multiple files with the same filename.

$ skicka ls /
skicka: /myfile.txt: duplicate file found on Google Drive

This is expected behaviour as commented in skicka.go.

            // This shouldn't happen in principle, but Drive does
            // allow multiple files to have the same title. It's not
            // obvious how to reconcile this with Unix file
            // semantics, so we just disallow it entirely.

It would be also better to describe about this in README.

'uploadtar' option

As a workaround for the slowness of backing up lots of small files, it would be fairly easy to use Go's 'tar' file generation functionality from the stdlib to create and upload a tar file of a local directory hierarchy. (Of course, this would be an all-or-nothing thing, always uploading everything.)

feature request: chown

Useful for managing quotas when files are shared. It's a pretty minor feature, but I thought I'd give others an opportunity to +1 this if they also want it.

> 100%

2/2 Uploads now, it has carried on past 100%. All the files appear to be there. I'm not sure how long it would go as I have Ctrl+C's it.

It was compiled using go 1.2 on ubuntu 14.04 LTS

dan@georgeiii:~$ skicka upload /srv/samba/photos/Pictures/2011/2011-01-11/ /Pictures/2011/2011-01-11/
skicka: Getting list of files to upload... Done. Starting upload.
974.62 MB / 563.64 MB [======================================] 172.91 % -3h59m0s

dan@georgeiii:~$ skicka upload /srv/samba/photos/Pictures/2011/ /Pictures/2011/
skicka: Getting list of files to upload... Done. Starting upload.
7.48 GB / 6.86 GB [==========================================] 109.05 % -6h9m26s

Other than that, it is awesome, thanks Matt.

panic: Drive path . doesn't start with base path / prefix!

This happens when I try to download from the gdrive root.
$ skicka download / localdir
So it makes sense that line 268 in download.go wouldn't get triggered, and will leave the '/' there, but . . .

I wonder if this has anything to do with . . .

commit a85631d
Author: Matt Pharr [email protected]
Date: Mon Apr 6 17:46:19 2015 -0700

Name the root directory "." rather than “/“.

(Simplifies a bit of code)

Add `fsck` command to list (and possibly delete) duplicate files

From the scenario in issue #18, it would be nice to be able to check the Google Drive folder in one go and get the full list of duplicate files, instead of having the command fail after a single duplicate is found.

Even better would be to have an option to automatically delete the duplicate files if other checks pass (at least checking if metadata and file contents are identical).

'rm' hangs on exit

Both 'rm' and 'rm -r' always hangs (for me) and needs to be stopped with CTRL-C. The intended content is however correctly deleted.

kassai@box:/media/photos$ skicka -debug -verbose rm /backup/katalog/testfil
^Ckassai@box:/media/photos$ skicka -debug -verbose rm -r /backup/katalog/
^C

I run it inside of GNU screen and am logged in to my Gdrive through a web browser while executing the code (I have a hard time seeing that it'd be relevant).

symbolic links are all ignored

if a directory is composed of a lot of symbolic links skicka will fail to resolve them. It will ignore them all.

skicka/upload.go

Lines 680 to 682 in 31f6c0c

if (info.Mode() & os.ModeSymlink) != 0 {
fmt.Printf("skicka: ignoring symlink \"%s\".\n", path)
return nil

ideally there should be a parameter:

-L Follow symbolic links.

As there is in the GNU program find.

screen shot 2015-03-02 at 5 37 40 pm

Set the modifiedDate property on upload

You are setting the ModificationTime property on the file when uploading to Drive. But it would be nice if the native modifiedDate field were also set. This would allow the proper date/time to be reflected in the Drive GUI and other tools. Note that you'll also need to set the setModifiedDate parameter if you are updating an existing file.

It would be excellent if this functionality could be added to skicka and then applied to already uploaded files, since it is just a metadata change.

potential race condition with large upload tasks

There seems to be a concurrency related issue with large uploads.

I have a large upload task of ~60k files and 100GiB total size. I have done >10 of attempts to upload this, and it has always failed at some random point during the upload. The upload stops to error skicka: …filename…: googleapi: Error 404: File not found: …id…, notFound or couldn't run Google Drive query: googleapi: Error 400: Invalid Value, invalid. I've always started a new upload (ie. to a new, non-existing Drive path), since getting the list of files of an interrupted download is very slow. Also, the creation of all paths (the first step in upload) succeeds, the error happens when actually uploading the file contents.

After suspecting this, I have tried with both higher and lower nWorkers values. With higher values it seemed to die earlier, and with value 1 the transfer succeeded in first attempt:

106.30 GB / 106.30 GB [=====================================] 100.00 % 71h15m39s
skicka: preparation time 0s, sync time 71h 15m 55s
skicka: updated 58121 Drive files, 0 local files
skicka: 0 B read from disk, 0 B written to disk
skicka: 106.30 GiB uploaded (434.44 kiB/s), 0 B downloaded (0 B/s)
skicka: 129.20 MiB peak memory used

Unforunately this is hard to reproduce exactly. The skicka version was ac702d2 .. this version reproduced both error cases above and the final success (with nWorkers := 1).

Skicka fails on upload

I started an upload to Google Drive that was terminated due to some network problem. Then, when attempting to restart I get the message:

"duplicate file found on Google Drive"

Grateful for ideas on how to solve this!

Add a "flaky" mode for testing/debugging?

If might be worthwhile to add a mode that injects intentional failures of various HTTP transactions and Google Drive API calls (403 errors, 5xx errors, etc.), in order to more thoroughly test all of the error handling and retry paths.

error when download - undefined: strings.TrimSuffix

After running the command: go build github.com/google/skicka

I get the following:
# github.com/google/skicka
/usr/lib/go/src/pkg/github.com/google/skicka/skicka.go:2065: undefined: strings.TrimSuffix

Using Ubuntu 13 32-bit server via SSH from a Chromebook

du doesn't properly report child directory usage

If we have a Drive folder hierarchy like

Pictures/
Pictures/2012/
Pictures/2012/spring/
Pictures/2012/summer/

and so forth, then 'skicka du' reports the usage of /Pictures/2012 as just the amount of stuff immediately in that folder; it doesn't include the usage of the child folders.

Usage of ls -ll

It is great to be able to extract MD5 checksums with "ls -ll". I After uploading files, I use "ls -ll" to compare the gdrive checksums with local hashes dumped with "md5deep -l".

Comparing the checksums from the uploaded files with the list generated by md5deep is a non-trivial exercise for me. I use sed, cut, grep and some regexp magic to present a usable list from "ls -ll" output, that can be compared to the "md5deep" output.

Is there an easier way to achieve this?

sort files by size to improve upload performance

Currently, if an upload has a mix of large and small files, it may have periods of low performance where it's working on small files only, and it's limited by file creation turnaround, even if it's bandwidth limited other times.

A better approach would be to have one worker thread process files going from largest to smallest and all other worker threads process files from smallest to largest. This should be much better at avoiding the variation in bandwidth usage (and thus in getting the full upload done more quickly.)

Support proxy

You know Google services are blocked in China. It would be nice to support HTTP, or even SOCKS.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.