mirror of https://github.com/vitalif/grive2
Compare commits
54 Commits
Author | SHA1 | Date |
---|---|---|
|
d03c4a24ce | |
|
328987ec34 | |
|
6645206d27 | |
![]() |
6901fbb169 | |
![]() |
48f5f0e52f | |
![]() |
e6fcc637f8 | |
![]() |
dedb762b74 | |
![]() |
d55fe7f5eb | |
![]() |
03a2c58403 | |
![]() |
b112fccd37 | |
![]() |
cb3c586862 | |
![]() |
3a28149bad | |
![]() |
e36f362abb | |
![]() |
30763e2f9d | |
![]() |
814b724cc4 | |
![]() |
050fcf53a0 | |
![]() |
9076e3aed2 | |
![]() |
27ca714e56 | |
![]() |
e0965f7fb8 | |
![]() |
5510ca1b06 | |
![]() |
4dfc9a5461 | |
![]() |
378df2867b | |
![]() |
0b53b08f57 | |
![]() |
d7008b81c1 | |
![]() |
1bab757298 | |
![]() |
c7a949dedd | |
![]() |
a8b84930f9 | |
![]() |
97a97265fd | |
![]() |
7b42e2da5b | |
![]() |
ffb744a59b | |
![]() |
03bbc20892 | |
![]() |
1456e6e0ba | |
![]() |
2ae61ab1e6 | |
![]() |
a295641cb0 | |
![]() |
2ddc0230da | |
![]() |
58a689a3db | |
![]() |
af2a6de268 | |
![]() |
fa3c39480a | |
![]() |
dc1946498d | |
![]() |
6aeec25778 | |
![]() |
b4d6ac055f | |
|
a3cce71643 | |
![]() |
37df02adff | |
![]() |
94182975db | |
![]() |
de6404b246 | |
![]() |
bdcb76efc0 | |
![]() |
79312b9c53 | |
![]() |
ad7844ba29 | |
|
39299096cf | |
![]() |
fe17d715fc | |
![]() |
6354689a93 | |
![]() |
7ef50e9523 | |
![]() |
e972a77790 | |
![]() |
8e3c3d25cb |
|
@ -23,3 +23,5 @@ debian/grive/
|
||||||
debian/.debhelper
|
debian/.debhelper
|
||||||
|
|
||||||
obj-x86_64-linux-gnu/
|
obj-x86_64-linux-gnu/
|
||||||
|
|
||||||
|
.idea
|
||||||
|
|
|
@ -1,15 +1,27 @@
|
||||||
cmake_minimum_required(VERSION 2.8)
|
cmake_minimum_required(VERSION 2.8)
|
||||||
|
project(grive2)
|
||||||
|
|
||||||
include(GNUInstallDirs)
|
include(GNUInstallDirs)
|
||||||
|
|
||||||
# Grive version. remember to update it for every new release!
|
# Grive version. remember to update it for every new release!
|
||||||
set( GRIVE_VERSION "0.5.1" )
|
set( GRIVE_VERSION "0.5.3" CACHE STRING "Grive version" )
|
||||||
|
message(WARNING "Version to build: ${GRIVE_VERSION}")
|
||||||
|
|
||||||
# common compile options
|
# common compile options
|
||||||
add_definitions( -DVERSION="${GRIVE_VERSION}" )
|
add_definitions( -DVERSION="${GRIVE_VERSION}" )
|
||||||
add_definitions( -D_FILE_OFFSET_BITS=64 -std=c++0x )
|
add_definitions( -D_FILE_OFFSET_BITS=64 -std=c++0x )
|
||||||
|
if ( APPLE )
|
||||||
|
add_definitions( -Doff64_t=off_t )
|
||||||
|
endif ( APPLE )
|
||||||
|
|
||||||
|
find_program(
|
||||||
|
HAVE_SYSTEMD systemd
|
||||||
|
PATHS /lib/systemd /usr/lib/systemd
|
||||||
|
NO_DEFAULT_PATH
|
||||||
|
)
|
||||||
|
if ( HAVE_SYSTEMD )
|
||||||
|
add_subdirectory( systemd )
|
||||||
|
endif( HAVE_SYSTEMD )
|
||||||
|
|
||||||
add_subdirectory( systemd )
|
|
||||||
add_subdirectory( libgrive )
|
add_subdirectory( libgrive )
|
||||||
add_subdirectory( grive )
|
add_subdirectory( grive )
|
||||||
|
|
49
Dockerfile
49
Dockerfile
|
@ -1,32 +1,27 @@
|
||||||
FROM ubuntu:16.04
|
FROM alpine:3.7 as build
|
||||||
|
|
||||||
RUN apt-get update && \
|
RUN apk add git make cmake g++ libgcrypt-dev yajl-dev yajl \
|
||||||
apt-get install --yes --no-install-recommends g++ cmake build-essential \
|
boost-dev curl-dev expat-dev cppunit-dev binutils-dev \
|
||||||
libgcrypt11-dev libyajl-dev libboost-all-dev \
|
pkgconfig \
|
||||||
libcurl4-openssl-dev libexpat1-dev libcppunit-dev \
|
&& git clone https://github.com/vitalif/grive2.git \
|
||||||
binutils-dev pkg-config zlib1g-dev && \
|
&& mkdir grive2/build \
|
||||||
rm -rf /var/cache/apt/archives /var/lib/apt/lists/*
|
&& cd grive2/build \
|
||||||
|
&& cmake .. \
|
||||||
|
&& make -j4 \
|
||||||
|
&& make install \
|
||||||
|
&& cd ../.. \
|
||||||
|
&& rm -rf grive2 \
|
||||||
|
&& mkdir /drive
|
||||||
|
|
||||||
ADD https://github.com/Yelp/dumb-init/releases/download/v1.2.1/dumb-init_1.2.1_amd64 /usr/local/bin/dumb-init
|
FROM alpine:3.7
|
||||||
|
COPY --from=build /usr/local/bin/grive /bin/grive
|
||||||
RUN chmod +x /usr/local/bin/dumb-init
|
ADD https://github.com/Yelp/dumb-init/releases/download/v1.2.1/dumb-init_1.2.1_amd64 /bin/dumb-init
|
||||||
|
RUN chmod 777 /bin/dumb-init /bin/grive \
|
||||||
ADD . /grive2
|
&& mkdir /data \
|
||||||
|
&& apk add yajl-dev curl-dev libgcrypt \
|
||||||
RUN cd /grive2 && \
|
boost-program_options boost-regex libstdc++ boost-system boost-dev binutils-dev \
|
||||||
mkdir build && \
|
&& apk add boost-filesystem --repository=http://dl-cdn.alpinelinux.org/alpine/edge/main
|
||||||
cd build && \
|
|
||||||
cmake .. && \
|
|
||||||
make -j4 && \
|
|
||||||
mv /grive2/build/grive/grive /usr/local/bin/grive && \
|
|
||||||
rm -rf /grive2
|
|
||||||
|
|
||||||
VOLUME /data
|
VOLUME /data
|
||||||
|
|
||||||
WORKDIR /data
|
WORKDIR /data
|
||||||
|
ENTRYPOINT ["dumb-init", "grive"]
|
||||||
ENTRYPOINT ["dumb-init", "/usr/local/bin/grive"]
|
|
||||||
|
|
||||||
|
|
||||||
# docker build -t grive2 .
|
|
||||||
# docker run --name grive2 --rm -it -v $PWD:/data grive2:latest
|
|
||||||
|
|
73
README.md
73
README.md
|
@ -1,6 +1,6 @@
|
||||||
# Grive2 0.5.2-dev
|
# Grive2 0.5.3
|
||||||
|
|
||||||
13 Nov 2019, Vitaliy Filippov
|
09 Nov 2022, Vitaliy Filippov
|
||||||
|
|
||||||
http://yourcmc.ru/wiki/Grive2
|
http://yourcmc.ru/wiki/Grive2
|
||||||
|
|
||||||
|
@ -39,10 +39,10 @@ grive -a
|
||||||
|
|
||||||
A URL should be printed. Go to the link. You will need to login to your Google
|
A URL should be printed. Go to the link. You will need to login to your Google
|
||||||
account if you haven't done so. After granting the permission to Grive, the
|
account if you haven't done so. After granting the permission to Grive, the
|
||||||
browser will show you an authenication code. Copy-and-paste that to the
|
authorization code will be forwarded to the Grive application and you will be
|
||||||
standard input of Grive.
|
redirected to a localhost web page confirming the authorization.
|
||||||
|
|
||||||
If everything works fine, Grive will create .grive and .grive_state files in your
|
If everything works fine, Grive will create .grive and .grive\_state files in your
|
||||||
current directory. It will also start downloading files from your Google Drive to
|
current directory. It will also start downloading files from your Google Drive to
|
||||||
your current directory.
|
your current directory.
|
||||||
|
|
||||||
|
@ -90,15 +90,18 @@ Prepare a Google Drive folder in your $HOME directory with `grive -a`.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# 'google-drive' is the name of your Google Drive folder in your $HOME directory
|
# 'google-drive' is the name of your Google Drive folder in your $HOME directory
|
||||||
systemctl --user enable grive-timer@$(systemd-escape google-drive).timer
|
systemctl --user enable grive@$(systemd-escape google-drive).service
|
||||||
systemctl --user start grive-timer@$(systemd-escape google-drive).timer
|
systemctl --user start grive@$(systemd-escape google-drive).service
|
||||||
systemctl --user enable grive-changes@$(systemd-escape google-drive).service
|
|
||||||
systemctl --user start grive-changes@$(systemd-escape google-drive).service
|
|
||||||
```
|
```
|
||||||
|
|
||||||
You can enable and start these two units for multiple folders in your `$HOME`
|
You can enable and start this unit for multiple folders in your `$HOME`
|
||||||
directory if you need to sync with multiple google accounts.
|
directory if you need to sync with multiple google accounts.
|
||||||
|
|
||||||
|
You can also only enable the time based syncing or the changes based syncing
|
||||||
|
by only directly enabling and starting the corresponding unit:
|
||||||
|
`grive-changes@$(systemd-escape google-drive).service` or
|
||||||
|
`grive-timer@$(systemd-escape google-drive).timer`.
|
||||||
|
|
||||||
### Shared files
|
### Shared files
|
||||||
|
|
||||||
Files and folders which are shared with you don't automatically show up in
|
Files and folders which are shared with you don't automatically show up in
|
||||||
|
@ -106,6 +109,37 @@ your folder. They need to be added explicitly to your Google Drive: go to the
|
||||||
Google Drive website, right click on the file or folder and chose 'Add to My
|
Google Drive website, right click on the file or folder and chose 'Add to My
|
||||||
Drive'.
|
Drive'.
|
||||||
|
|
||||||
|
### Different OAuth2 client to workaround over quota and google approval issues
|
||||||
|
|
||||||
|
Google recently started to restrict access for unapproved applications:
|
||||||
|
https://developers.google.com/drive/api/v3/about-auth?hl=ru
|
||||||
|
|
||||||
|
Grive2 is currently awaiting approval but it seems it will take forever.
|
||||||
|
Also even if they approve it the default Client ID supplied with grive may
|
||||||
|
exceed quota and grive will then fail to sync.
|
||||||
|
|
||||||
|
You can supply your own OAuth2 client credentials to work around these problems
|
||||||
|
by following these steps:
|
||||||
|
|
||||||
|
1. Go to https://console.developers.google.com/apis/api/drive.googleapis.com
|
||||||
|
2. Choose a project (you might need to create one first)
|
||||||
|
3. Go to https://console.developers.google.com/apis/library/drive.googleapis.com and
|
||||||
|
"Enable" the Google Drive APIs
|
||||||
|
4. Go to https://console.cloud.google.com/apis/credentials and click "Create credentials > Help me choose"
|
||||||
|
5. In the "Find out what credentials you need" dialog, choose:
|
||||||
|
- Which API are you using: "Google Drive API"
|
||||||
|
- Where will you be calling the API from: "Other UI (...CLI...)"
|
||||||
|
- What data will you be accessing: "User Data"
|
||||||
|
6. In the next steps create a client id (name doesn't matter) and
|
||||||
|
setup the consent screen (defaults are ok, no need for any URLs)
|
||||||
|
7. The needed "Client ID" and "Client Secret" are either in the shown download
|
||||||
|
or can later found by clicking on the created credential on
|
||||||
|
https://console.developers.google.com/apis/credentials/
|
||||||
|
8. When you change client ID/secret in an existing Grive folder you must first delete
|
||||||
|
the old `.grive` configuration file.
|
||||||
|
9. Call `grive -a --id <client_id> --secret <client_secret>` and follow the steps
|
||||||
|
to authenticate the OAuth2 client to allow it to access your drive folder.
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
For the detailed instructions, see http://yourcmc.ru/wiki/Grive2#Installation
|
For the detailed instructions, see http://yourcmc.ru/wiki/Grive2#Installation
|
||||||
|
@ -129,13 +163,13 @@ There are also some optional dependencies:
|
||||||
On a Debian/Ubuntu/Linux Mint machine just run the following command to install all
|
On a Debian/Ubuntu/Linux Mint machine just run the following command to install all
|
||||||
these packages:
|
these packages:
|
||||||
|
|
||||||
sudo apt-get install git cmake build-essential libgcrypt11-dev libyajl-dev \
|
sudo apt-get install git cmake build-essential libgcrypt20-dev libyajl-dev \
|
||||||
libboost-all-dev libcurl4-openssl-dev libexpat1-dev libcppunit-dev binutils-dev \
|
libboost-all-dev libcurl4-openssl-dev libexpat1-dev libcppunit-dev binutils-dev \
|
||||||
debhelper zlib1g-dev dpkg-dev pkg-config
|
debhelper zlib1g-dev dpkg-dev pkg-config
|
||||||
|
|
||||||
Fedora:
|
Fedora:
|
||||||
|
|
||||||
sudo dnf install git cmake libgcrypt-devel gcc-c++ libstdc++ yajl-devel boost libcurl-devel expat-devel binutils zlib
|
sudo dnf install git cmake libgcrypt-devel gcc-c++ libstdc++ yajl-devel boost-devel libcurl-devel expat-devel binutils zlib
|
||||||
|
|
||||||
|
|
||||||
FreeBSD:
|
FreeBSD:
|
||||||
|
@ -147,7 +181,7 @@ FreeBSD:
|
||||||
On a Debian/Ubuntu/Linux Mint you can use `dpkg-buildpackage` utility from `dpkg-dev` package
|
On a Debian/Ubuntu/Linux Mint you can use `dpkg-buildpackage` utility from `dpkg-dev` package
|
||||||
to build grive. Just clone the repository, `cd` into it and run
|
to build grive. Just clone the repository, `cd` into it and run
|
||||||
|
|
||||||
dpkg-buildpackage -j4
|
dpkg-buildpackage -j4 --no-sign
|
||||||
|
|
||||||
### Manual build
|
### Manual build
|
||||||
|
|
||||||
|
@ -159,9 +193,20 @@ Grive uses cmake to build. Basic install sequence is
|
||||||
make -j4
|
make -j4
|
||||||
sudo make install
|
sudo make install
|
||||||
|
|
||||||
|
Alternativly you can define your own client_id and client_secret during build
|
||||||
|
|
||||||
|
mkdir build
|
||||||
|
cd build
|
||||||
|
cmake .. "-DAPP_ID:STRING=<client_id>" "-DAPP_SECRET:STRING=<client_secret>"
|
||||||
|
make -j4
|
||||||
|
sudo make install
|
||||||
|
|
||||||
## Version History
|
## Version History
|
||||||
|
|
||||||
### Grive2 v0.5.2-dev
|
### Grive2 v0.5.3
|
||||||
|
|
||||||
|
- Implement Google OAuth loopback IP redirect flow
|
||||||
|
- Various small fixes
|
||||||
|
|
||||||
### Grive2 v0.5.1
|
### Grive2 v0.5.1
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,15 @@
|
||||||
grive2 (0.5.1+git20160731) unstable; urgency=medium
|
grive2 (0.5.3) unstable; urgency=medium
|
||||||
|
|
||||||
|
* Implement Google OAuth loopback IP redirect flow
|
||||||
|
* Various small fixes
|
||||||
|
|
||||||
|
-- Vitaliy Filippov <vitalif@yourcmc.ru> Wed, 09 Nov 2022 12:42:28 +0300
|
||||||
|
|
||||||
|
grive2 (0.5.2+git20210315) unstable; urgency=medium
|
||||||
|
|
||||||
* Newer dev version
|
* Newer dev version
|
||||||
|
* Add systemd unit files and helper script for automatic syncs
|
||||||
|
* Add possibility to change client id and secret and save it between runs
|
||||||
|
|
||||||
-- Vitaliy Filippov <vitalif@yourcmc.ru> Wed, 31 Jul 2016 22:04:53 +0300
|
-- Vitaliy Filippov <vitalif@yourcmc.ru> Wed, 31 Jul 2016 22:04:53 +0300
|
||||||
|
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
7
|
11
|
||||||
|
|
|
@ -2,7 +2,7 @@ Source: grive2
|
||||||
Section: net
|
Section: net
|
||||||
Priority: optional
|
Priority: optional
|
||||||
Maintainer: Vitaliy Filippov <vitalif@mail.ru>
|
Maintainer: Vitaliy Filippov <vitalif@mail.ru>
|
||||||
Build-Depends: debhelper, cmake, pkg-config, zlib1g-dev, libcurl4-openssl-dev | libcurl4-gnutls-dev, libstdc++-7-dev |libstdc++-6-dev | libstdc++6-4.4-dev | libstdc++-4.9-dev | libstdc++-5-dev, libboost-filesystem-dev, libboost-program-options-dev, libboost-test-dev, libboost-regex-dev, libexpat1-dev, binutils-dev, libgcrypt-dev, libyajl-dev
|
Build-Depends: debhelper, cmake, pkg-config, zlib1g-dev, libcurl4-openssl-dev | libcurl4-gnutls-dev, libboost-filesystem-dev, libboost-program-options-dev, libboost-test-dev, libboost-regex-dev, libexpat1-dev, libgcrypt-dev, libyajl-dev
|
||||||
Standards-Version: 3.9.6
|
Standards-Version: 3.9.6
|
||||||
Homepage: https://yourcmc.ru/wiki/Grive2
|
Homepage: https://yourcmc.ru/wiki/Grive2
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,7 @@
|
||||||
#!/usr/bin/make -f
|
#!/usr/bin/make -f
|
||||||
|
|
||||||
|
override_dh_auto_configure:
|
||||||
|
dh_auto_configure -- -DHAVE_SYSTEMD=1
|
||||||
|
|
||||||
%:
|
%:
|
||||||
dh $@ --buildsystem=cmake --parallel
|
dh $@ --buildsystem=cmake --parallel --builddirectory=build
|
||||||
|
|
|
@ -20,6 +20,17 @@ target_link_libraries( grive_executable
|
||||||
grive
|
grive
|
||||||
)
|
)
|
||||||
|
|
||||||
|
set(DEFAULT_APP_ID "615557989097-i93d4d1ojpen0m0dso18ldr6orjkidgf.apps.googleusercontent.com")
|
||||||
|
set(DEFAULT_APP_SECRET "xiM8Apu_WuRRdheNelJcNtOD")
|
||||||
|
set(APP_ID ${DEFAULT_APP_ID} CACHE STRING "Application Id")
|
||||||
|
set(APP_SECRET ${DEFAULT_APP_SECRET} CACHE STRING "Application Secret")
|
||||||
|
|
||||||
|
target_compile_definitions ( grive_executable
|
||||||
|
PRIVATE
|
||||||
|
-DAPP_ID="${APP_ID}"
|
||||||
|
-DAPP_SECRET="${APP_SECRET}"
|
||||||
|
)
|
||||||
|
|
||||||
set_target_properties( grive_executable
|
set_target_properties( grive_executable
|
||||||
PROPERTIES OUTPUT_NAME grive
|
PROPERTIES OUTPUT_NAME grive
|
||||||
)
|
)
|
||||||
|
|
|
@ -46,8 +46,8 @@
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
const std::string default_id = "615557989097-i93d4d1ojpen0m0dso18ldr6orjkidgf.apps.googleusercontent.com" ;
|
const std::string default_id = APP_ID ;
|
||||||
const std::string default_secret = "xiM8Apu_WuRRdheNelJcNtOD" ;
|
const std::string default_secret = APP_SECRET ;
|
||||||
|
|
||||||
using namespace gr ;
|
using namespace gr ;
|
||||||
namespace po = boost::program_options;
|
namespace po = boost::program_options;
|
||||||
|
@ -111,8 +111,9 @@ int Main( int argc, char **argv )
|
||||||
( "help,h", "Produce help message" )
|
( "help,h", "Produce help message" )
|
||||||
( "version,v", "Display Grive version" )
|
( "version,v", "Display Grive version" )
|
||||||
( "auth,a", "Request authorization token" )
|
( "auth,a", "Request authorization token" )
|
||||||
( "id,i", po::value<std::string>(), "Authentication ID")
|
( "id,i", po::value<std::string>(), "Authentication ID")
|
||||||
( "secret,e", po::value<std::string>(), "Authentication secret")
|
( "secret,e", po::value<std::string>(), "Authentication secret")
|
||||||
|
( "print-url", "Only print url for request")
|
||||||
( "path,p", po::value<std::string>(), "Path to working copy root")
|
( "path,p", po::value<std::string>(), "Path to working copy root")
|
||||||
( "dir,s", po::value<std::string>(), "Single subdirectory to sync")
|
( "dir,s", po::value<std::string>(), "Single subdirectory to sync")
|
||||||
( "verbose,V", "Verbose mode. Enable more messages than normal.")
|
( "verbose,V", "Verbose mode. Enable more messages than normal.")
|
||||||
|
@ -174,46 +175,50 @@ int Main( int argc, char **argv )
|
||||||
http->SetProgressReporter( pb.get() );
|
http->SetProgressReporter( pb.get() );
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string id = default_id;
|
|
||||||
std::string secret = default_secret;
|
|
||||||
|
|
||||||
if( vm.count( "id" ) )
|
|
||||||
{
|
|
||||||
id = vm["id"].as<std::string>();
|
|
||||||
}
|
|
||||||
|
|
||||||
if( vm.count( "secret" ) )
|
|
||||||
{
|
|
||||||
secret = vm["secret"].as<std::string>();
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( vm.count( "auth" ) )
|
if ( vm.count( "auth" ) )
|
||||||
{
|
{
|
||||||
|
std::string id = vm.count( "id" ) > 0
|
||||||
|
? vm["id"].as<std::string>()
|
||||||
|
: default_id ;
|
||||||
|
std::string secret = vm.count( "secret" ) > 0
|
||||||
|
? vm["secret"].as<std::string>()
|
||||||
|
: default_secret ;
|
||||||
|
|
||||||
OAuth2 token( http.get(), id, secret ) ;
|
OAuth2 token( http.get(), id, secret ) ;
|
||||||
|
|
||||||
|
if ( vm.count("print-url") )
|
||||||
|
{
|
||||||
|
std::cout << token.MakeAuthURL() << std::endl ;
|
||||||
|
return 0 ;
|
||||||
|
}
|
||||||
|
|
||||||
std::cout
|
std::cout
|
||||||
<< "-----------------------\n"
|
<< "-----------------------\n"
|
||||||
<< "Please go to this URL and get an authentication code:\n\n"
|
<< "Please open this URL in your browser to authenticate Grive2:\n\n"
|
||||||
<< token.MakeAuthURL()
|
<< token.MakeAuthURL()
|
||||||
<< std::endl ;
|
<< std::endl ;
|
||||||
|
|
||||||
std::cout
|
if ( !token.GetCode() )
|
||||||
<< "\n-----------------------\n"
|
{
|
||||||
<< "Please input the authentication code here: " << std::endl ;
|
std::cout << "Authentication failed\n";
|
||||||
std::string code ;
|
return -1;
|
||||||
std::cin >> code ;
|
}
|
||||||
|
|
||||||
token.Auth( code ) ;
|
|
||||||
|
|
||||||
// save to config
|
// save to config
|
||||||
|
config.Set( "id", Val( id ) ) ;
|
||||||
|
config.Set( "secret", Val( secret ) ) ;
|
||||||
config.Set( "refresh_token", Val( token.RefreshToken() ) ) ;
|
config.Set( "refresh_token", Val( token.RefreshToken() ) ) ;
|
||||||
config.Save() ;
|
config.Save() ;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string refresh_token ;
|
std::string refresh_token ;
|
||||||
|
std::string id ;
|
||||||
|
std::string secret ;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
refresh_token = config.Get("refresh_token").Str() ;
|
refresh_token = config.Get("refresh_token").Str() ;
|
||||||
|
id = config.Get("id").Str() ;
|
||||||
|
secret = config.Get("secret").Str() ;
|
||||||
}
|
}
|
||||||
catch ( Exception& e )
|
catch ( Exception& e )
|
||||||
{
|
{
|
||||||
|
@ -224,7 +229,7 @@ int Main( int argc, char **argv )
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
OAuth2 token( http.get(), refresh_token, id, secret ) ;
|
OAuth2 token( http.get(), refresh_token, id, secret ) ;
|
||||||
AuthAgent agent( token, http.get() ) ;
|
AuthAgent agent( token, http.get() ) ;
|
||||||
v2::Syncer2 syncer( &agent );
|
v2::Syncer2 syncer( &agent );
|
||||||
|
|
|
@ -4,6 +4,7 @@ set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/Modules/")
|
||||||
|
|
||||||
find_package(LibGcrypt REQUIRED)
|
find_package(LibGcrypt REQUIRED)
|
||||||
find_package(CURL REQUIRED)
|
find_package(CURL REQUIRED)
|
||||||
|
find_package(Backtrace)
|
||||||
find_package(Boost 1.40.0 COMPONENTS program_options filesystem unit_test_framework regex system REQUIRED)
|
find_package(Boost 1.40.0 COMPONENTS program_options filesystem unit_test_framework regex system REQUIRED)
|
||||||
find_package(BFD)
|
find_package(BFD)
|
||||||
find_package(CppUnit)
|
find_package(CppUnit)
|
||||||
|
@ -19,15 +20,15 @@ IF ( CPPUNIT_FOUND )
|
||||||
set( OPT_INCS ${CPPUNIT_INCLUDE_DIR} )
|
set( OPT_INCS ${CPPUNIT_INCLUDE_DIR} )
|
||||||
ENDIF ( CPPUNIT_FOUND )
|
ENDIF ( CPPUNIT_FOUND )
|
||||||
|
|
||||||
# build bfd classes if libbfd is found
|
# build bfd classes if libbfd and the backtrace library is found
|
||||||
if ( BFD_FOUND )
|
if ( BFD_FOUND AND Backtrace_FOUND )
|
||||||
set( OPT_LIBS ${DL_LIBRARY} ${BFD_LIBRARY} )
|
set( OPT_LIBS ${DL_LIBRARY} ${BFD_LIBRARY} ${Backtrace_LIBRARY} )
|
||||||
file( GLOB OPT_SRC
|
file( GLOB OPT_SRC
|
||||||
src/bfd/*.cc
|
src/bfd/*.cc
|
||||||
)
|
)
|
||||||
add_definitions( -DHAVE_BFD )
|
add_definitions( -DHAVE_BFD )
|
||||||
|
|
||||||
endif ( BFD_FOUND )
|
endif ( BFD_FOUND AND Backtrace_FOUND )
|
||||||
|
|
||||||
if ( IBERTY_FOUND )
|
if ( IBERTY_FOUND )
|
||||||
set( OPT_LIBS ${OPT_LIBS} ${IBERTY_LIBRARY} )
|
set( OPT_LIBS ${OPT_LIBS} ${IBERTY_LIBRARY} )
|
||||||
|
|
|
@ -30,6 +30,10 @@ Feed::Feed( const std::string &url ):
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Feed::~Feed()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
Feed::iterator Feed::begin() const
|
Feed::iterator Feed::begin() const
|
||||||
{
|
{
|
||||||
return m_entries.begin() ;
|
return m_entries.begin() ;
|
||||||
|
|
|
@ -41,6 +41,7 @@ public :
|
||||||
public :
|
public :
|
||||||
Feed( const std::string& url );
|
Feed( const std::string& url );
|
||||||
virtual bool GetNext( http::Agent *http ) = 0 ;
|
virtual bool GetNext( http::Agent *http ) = 0 ;
|
||||||
|
virtual ~Feed() = 0 ;
|
||||||
iterator begin() const ;
|
iterator begin() const ;
|
||||||
iterator end() const ;
|
iterator end() const ;
|
||||||
|
|
||||||
|
|
|
@ -49,9 +49,9 @@ SymbolInfo::SymbolInfo( )
|
||||||
m_impl->m_bfd = 0 ;
|
m_impl->m_bfd = 0 ;
|
||||||
m_impl->m_symbols = 0 ;
|
m_impl->m_symbols = 0 ;
|
||||||
m_impl->m_symbol_count = 0 ;
|
m_impl->m_symbol_count = 0 ;
|
||||||
|
|
||||||
bfd_init( ) ;
|
bfd_init( ) ;
|
||||||
|
|
||||||
// opening itself
|
// opening itself
|
||||||
bfd *b = bfd_openr( "/proc/self/exe", 0 ) ;
|
bfd *b = bfd_openr( "/proc/self/exe", 0 ) ;
|
||||||
if ( b == NULL )
|
if ( b == NULL )
|
||||||
|
@ -60,13 +60,13 @@ SymbolInfo::SymbolInfo( )
|
||||||
<< bfd_errmsg( bfd_get_error() ) << std::endl ;
|
<< bfd_errmsg( bfd_get_error() ) << std::endl ;
|
||||||
return ;
|
return ;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( bfd_check_format( b, bfd_archive ) )
|
if ( bfd_check_format( b, bfd_archive ) )
|
||||||
{
|
{
|
||||||
bfd_close( b ) ;
|
bfd_close( b ) ;
|
||||||
return ;
|
return ;
|
||||||
}
|
}
|
||||||
|
|
||||||
char **matching ;
|
char **matching ;
|
||||||
if ( !bfd_check_format_matches( b, bfd_object, &matching ) )
|
if ( !bfd_check_format_matches( b, bfd_object, &matching ) )
|
||||||
{
|
{
|
||||||
|
@ -78,7 +78,7 @@ SymbolInfo::SymbolInfo( )
|
||||||
std::cerr << bfd_get_filename( b ) << ": Matching formats: " ;
|
std::cerr << bfd_get_filename( b ) << ": Matching formats: " ;
|
||||||
for ( char **p = matching ; *p != 0 ; p++ )
|
for ( char **p = matching ; *p != 0 ; p++ )
|
||||||
std::cerr << " " << *p ;
|
std::cerr << " " << *p ;
|
||||||
|
|
||||||
std::cerr << std::endl ;
|
std::cerr << std::endl ;
|
||||||
std::free( matching ) ;
|
std::free( matching ) ;
|
||||||
}
|
}
|
||||||
|
@ -107,7 +107,7 @@ struct SymbolInfo::BacktraceInfo
|
||||||
const char *m_func_name ;
|
const char *m_func_name ;
|
||||||
unsigned int m_lineno ;
|
unsigned int m_lineno ;
|
||||||
unsigned int m_is_found ;
|
unsigned int m_is_found ;
|
||||||
|
|
||||||
static void Callback( bfd *abfd, asection *section, void* addr ) ;
|
static void Callback( bfd *abfd, asection *section, void* addr ) ;
|
||||||
} ;
|
} ;
|
||||||
|
|
||||||
|
@ -117,17 +117,24 @@ void SymbolInfo::BacktraceInfo::Callback( bfd *abfd, asection *section,
|
||||||
BacktraceInfo *info = (BacktraceInfo *)data ;
|
BacktraceInfo *info = (BacktraceInfo *)data ;
|
||||||
if ((section->flags & SEC_ALLOC) == 0)
|
if ((section->flags & SEC_ALLOC) == 0)
|
||||||
return ;
|
return ;
|
||||||
|
|
||||||
bfd_vma vma = bfd_get_section_vma(abfd, section);
|
// bfd_get_section_vma works up to 7b1cfbcf1a27951fb1b3a212995075dd6fdf985b,
|
||||||
|
// removed in 7c13bc8c91abf291f0206b6608b31955c5ea70d8 (binutils 2.33.1 or so)
|
||||||
|
// so it's substituted by its implementation to avoid checking for binutils
|
||||||
|
// version (which at least on Debian SID it's not that easy because the
|
||||||
|
// version.h is not included with the official package)
|
||||||
|
bfd_vma vma = section->vma;
|
||||||
|
|
||||||
unsigned long address = (unsigned long)(info->m_addr);
|
unsigned long address = (unsigned long)(info->m_addr);
|
||||||
if ( address < vma )
|
if ( address < vma )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
bfd_size_type size = bfd_section_size(abfd, section);
|
// bfd_section_size changed between the two objects described above,
|
||||||
|
// same rationale applies
|
||||||
|
bfd_size_type size = section->size;
|
||||||
if ( address > (vma + size))
|
if ( address > (vma + size))
|
||||||
return ;
|
return ;
|
||||||
|
|
||||||
const SymbolInfo *pthis = info->m_pthis ;
|
const SymbolInfo *pthis = info->m_pthis ;
|
||||||
info->m_is_found = bfd_find_nearest_line( abfd, section,
|
info->m_is_found = bfd_find_nearest_line( abfd, section,
|
||||||
pthis->m_impl->m_symbols,
|
pthis->m_impl->m_symbols,
|
||||||
|
@ -149,7 +156,7 @@ void SymbolInfo::PrintTrace( void *addr, std::ostream& os, std::size_t idx )
|
||||||
{
|
{
|
||||||
this, addr, 0, 0, 0, false
|
this, addr, 0, 0, 0, false
|
||||||
} ;
|
} ;
|
||||||
|
|
||||||
Dl_info sym ;
|
Dl_info sym ;
|
||||||
bfd_map_over_sections( m_impl->m_bfd,
|
bfd_map_over_sections( m_impl->m_bfd,
|
||||||
&SymbolInfo::BacktraceInfo::Callback,
|
&SymbolInfo::BacktraceInfo::Callback,
|
||||||
|
@ -165,7 +172,7 @@ if ( btinfo.m_is_found )
|
||||||
filename.erase( pos, std::strlen( SRC_DIR ) ) ;
|
filename.erase( pos, std::strlen( SRC_DIR ) ) ;
|
||||||
#endif
|
#endif
|
||||||
os << "#" << idx << " " << addr << " "
|
os << "#" << idx << " " << addr << " "
|
||||||
<< filename << ":" << btinfo.m_lineno
|
<< filename << ":" << btinfo.m_lineno
|
||||||
<< " "
|
<< " "
|
||||||
<< (btinfo.m_func_name != 0 ? Demangle(btinfo.m_func_name) : "" )
|
<< (btinfo.m_func_name != 0 ? Demangle(btinfo.m_func_name) : "" )
|
||||||
<< std::endl ;
|
<< std::endl ;
|
||||||
|
|
|
@ -36,6 +36,10 @@ Feed2::Feed2( const std::string& url ):
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Feed2::~Feed2()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
bool Feed2::GetNext( http::Agent *http )
|
bool Feed2::GetNext( http::Agent *http )
|
||||||
{
|
{
|
||||||
if ( m_next.empty() )
|
if ( m_next.empty() )
|
||||||
|
|
|
@ -31,6 +31,7 @@ class Feed2: public Feed
|
||||||
{
|
{
|
||||||
public :
|
public :
|
||||||
Feed2( const std::string& url ) ;
|
Feed2( const std::string& url ) ;
|
||||||
|
~Feed2() ;
|
||||||
bool GetNext( http::Agent *http ) ;
|
bool GetNext( http::Agent *http ) ;
|
||||||
} ;
|
} ;
|
||||||
|
|
||||||
|
|
|
@ -25,6 +25,13 @@
|
||||||
#include "http/Header.hh"
|
#include "http/Header.hh"
|
||||||
#include "util/log/Log.hh"
|
#include "util/log/Log.hh"
|
||||||
|
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <poll.h>
|
||||||
|
|
||||||
// for debugging
|
// for debugging
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
|
@ -50,18 +57,29 @@ OAuth2::OAuth2(
|
||||||
const std::string& client_id,
|
const std::string& client_id,
|
||||||
const std::string& client_secret ) :
|
const std::string& client_secret ) :
|
||||||
m_agent( agent ),
|
m_agent( agent ),
|
||||||
|
m_port( 0 ),
|
||||||
|
m_socket( -1 ),
|
||||||
m_client_id( client_id ),
|
m_client_id( client_id ),
|
||||||
m_client_secret( client_secret )
|
m_client_secret( client_secret )
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void OAuth2::Auth( const std::string& auth_code )
|
OAuth2::~OAuth2()
|
||||||
|
{
|
||||||
|
if ( m_socket >= 0 )
|
||||||
|
{
|
||||||
|
close( m_socket );
|
||||||
|
m_socket = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool OAuth2::Auth( const std::string& auth_code )
|
||||||
{
|
{
|
||||||
std::string post =
|
std::string post =
|
||||||
"code=" + auth_code +
|
"code=" + auth_code +
|
||||||
"&client_id=" + m_client_id +
|
"&client_id=" + m_client_id +
|
||||||
"&client_secret=" + m_client_secret +
|
"&client_secret=" + m_client_secret +
|
||||||
"&redirect_uri=" + "urn:ietf:wg:oauth:2.0:oob" +
|
"&redirect_uri=http%3A%2F%2Flocalhost:" + std::to_string( m_port ) + "%2Fauth" +
|
||||||
"&grant_type=authorization_code" ;
|
"&grant_type=authorization_code" ;
|
||||||
|
|
||||||
http::ValResponse resp ;
|
http::ValResponse resp ;
|
||||||
|
@ -77,19 +95,120 @@ void OAuth2::Auth( const std::string& auth_code )
|
||||||
{
|
{
|
||||||
Log( "Failed to obtain auth token: HTTP %1%, body: %2%",
|
Log( "Failed to obtain auth token: HTTP %1%, body: %2%",
|
||||||
code, m_agent->LastError(), log::error ) ;
|
code, m_agent->LastError(), log::error ) ;
|
||||||
BOOST_THROW_EXCEPTION( AuthFailed() );
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string OAuth2::MakeAuthURL()
|
std::string OAuth2::MakeAuthURL()
|
||||||
{
|
{
|
||||||
|
if ( !m_port )
|
||||||
|
{
|
||||||
|
sockaddr_storage addr = { 0 };
|
||||||
|
addr.ss_family = AF_INET;
|
||||||
|
m_socket = socket( AF_INET, SOCK_STREAM, 0 );
|
||||||
|
if ( m_socket < 0 )
|
||||||
|
throw std::runtime_error( std::string("socket: ") + strerror(errno) );
|
||||||
|
if ( bind( m_socket, (sockaddr*)&addr, sizeof( addr ) ) < 0 )
|
||||||
|
{
|
||||||
|
close( m_socket );
|
||||||
|
m_socket = -1;
|
||||||
|
throw std::runtime_error( std::string("bind: ") + strerror(errno) );
|
||||||
|
}
|
||||||
|
socklen_t len = sizeof( addr );
|
||||||
|
if ( getsockname( m_socket, (sockaddr *)&addr, &len ) == -1 )
|
||||||
|
{
|
||||||
|
close( m_socket );
|
||||||
|
m_socket = -1;
|
||||||
|
throw std::runtime_error( std::string("getsockname: ") + strerror(errno) );
|
||||||
|
}
|
||||||
|
m_port = ntohs(((sockaddr_in*)&addr)->sin_port);
|
||||||
|
if ( listen( m_socket, 128 ) < 0 )
|
||||||
|
{
|
||||||
|
close( m_socket );
|
||||||
|
m_socket = -1;
|
||||||
|
m_port = 0;
|
||||||
|
throw std::runtime_error( std::string("listen: ") + strerror(errno) );
|
||||||
|
}
|
||||||
|
}
|
||||||
return "https://accounts.google.com/o/oauth2/auth"
|
return "https://accounts.google.com/o/oauth2/auth"
|
||||||
"?scope=" + m_agent->Escape( "https://www.googleapis.com/auth/drive" ) +
|
"?scope=" + m_agent->Escape( "https://www.googleapis.com/auth/drive" ) +
|
||||||
"&redirect_uri=urn:ietf:wg:oauth:2.0:oob"
|
"&redirect_uri=http%3A%2F%2Flocalhost:" + std::to_string( m_port ) + "%2Fauth" +
|
||||||
"&response_type=code"
|
"&response_type=code"
|
||||||
"&client_id=" + m_client_id ;
|
"&client_id=" + m_client_id ;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool OAuth2::GetCode( )
|
||||||
|
{
|
||||||
|
sockaddr_storage addr = { 0 };
|
||||||
|
int peer_fd = -1;
|
||||||
|
while ( peer_fd < 0 )
|
||||||
|
{
|
||||||
|
socklen_t peer_addr_size = sizeof( addr );
|
||||||
|
peer_fd = accept( m_socket, (sockaddr*)&addr, &peer_addr_size );
|
||||||
|
if ( peer_fd == -1 && errno != EAGAIN && errno != EINTR )
|
||||||
|
throw std::runtime_error( std::string("accept: ") + strerror(errno) );
|
||||||
|
}
|
||||||
|
fcntl( peer_fd, F_SETFL, fcntl( peer_fd, F_GETFL, 0 ) | O_NONBLOCK );
|
||||||
|
struct pollfd pfd = (struct pollfd){
|
||||||
|
.fd = peer_fd,
|
||||||
|
.events = POLLIN|POLLRDHUP,
|
||||||
|
};
|
||||||
|
char buf[4096];
|
||||||
|
std::string request;
|
||||||
|
while ( true )
|
||||||
|
{
|
||||||
|
pfd.revents = 0;
|
||||||
|
poll( &pfd, 1, -1 );
|
||||||
|
if ( pfd.revents & POLLRDHUP )
|
||||||
|
break;
|
||||||
|
int r = 1;
|
||||||
|
while ( r > 0 )
|
||||||
|
{
|
||||||
|
r = read( peer_fd, buf, sizeof( buf ) );
|
||||||
|
if ( r > 0 )
|
||||||
|
request += std::string( buf, r );
|
||||||
|
else if ( r == 0 )
|
||||||
|
break;
|
||||||
|
else if ( errno != EAGAIN && errno != EINTR )
|
||||||
|
throw std::runtime_error( std::string("read: ") + strerror(errno) );
|
||||||
|
}
|
||||||
|
if ( r == 0 || ( r < 0 && request.find( "\n" ) > 0 ) ) // GET ... HTTP/1.1\r\n
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
bool ok = false;
|
||||||
|
if ( request.substr( 0, 10 ) == "GET /auth?" )
|
||||||
|
{
|
||||||
|
std::string line = request;
|
||||||
|
int p = line.find( "\n" );
|
||||||
|
if ( p > 0 )
|
||||||
|
line = line.substr( 0, p );
|
||||||
|
p = line.rfind( " " );
|
||||||
|
if ( p > 0 )
|
||||||
|
line = line.substr( 0, p );
|
||||||
|
p = line.find( "code=" );
|
||||||
|
if ( p > 0 )
|
||||||
|
line = line.substr( p+5 );
|
||||||
|
p = line.find( "&" );
|
||||||
|
if ( p > 0 )
|
||||||
|
line = line.substr( 0, p );
|
||||||
|
ok = Auth( line );
|
||||||
|
}
|
||||||
|
std::string response = ( ok
|
||||||
|
? "Authenticated successfully. Please close the page"
|
||||||
|
: "Authentication error. Please try again" );
|
||||||
|
response = "HTTP/1.1 200 OK\r\n"
|
||||||
|
"Content-Type: text/html; charset=utf-8\r\n"
|
||||||
|
"Connection: close\r\n"
|
||||||
|
"\r\n"+
|
||||||
|
response+
|
||||||
|
"\r\n";
|
||||||
|
write( peer_fd, response.c_str(), response.size() );
|
||||||
|
close( peer_fd );
|
||||||
|
return ok;
|
||||||
|
}
|
||||||
|
|
||||||
void OAuth2::Refresh( )
|
void OAuth2::Refresh( )
|
||||||
{
|
{
|
||||||
std::string post =
|
std::string post =
|
||||||
|
|
|
@ -41,13 +41,15 @@ public :
|
||||||
const std::string& refresh_code,
|
const std::string& refresh_code,
|
||||||
const std::string& client_id,
|
const std::string& client_id,
|
||||||
const std::string& client_secret ) ;
|
const std::string& client_secret ) ;
|
||||||
|
~OAuth2( ) ;
|
||||||
|
|
||||||
std::string Str() const ;
|
std::string Str() const ;
|
||||||
|
|
||||||
std::string MakeAuthURL() ;
|
std::string MakeAuthURL() ;
|
||||||
|
|
||||||
void Auth( const std::string& auth_code ) ;
|
bool Auth( const std::string& auth_code ) ;
|
||||||
void Refresh( ) ;
|
void Refresh( ) ;
|
||||||
|
bool GetCode( ) ;
|
||||||
|
|
||||||
std::string RefreshToken( ) const ;
|
std::string RefreshToken( ) const ;
|
||||||
std::string AccessToken( ) const ;
|
std::string AccessToken( ) const ;
|
||||||
|
@ -59,7 +61,9 @@ private :
|
||||||
std::string m_access ;
|
std::string m_access ;
|
||||||
std::string m_refresh ;
|
std::string m_refresh ;
|
||||||
http::Agent* m_agent ;
|
http::Agent* m_agent ;
|
||||||
|
int m_port ;
|
||||||
|
int m_socket ;
|
||||||
|
|
||||||
const std::string m_client_id ;
|
const std::string m_client_id ;
|
||||||
const std::string m_client_secret ;
|
const std::string m_client_secret ;
|
||||||
} ;
|
} ;
|
||||||
|
|
|
@ -38,6 +38,10 @@ const std::string default_root_folder = ".";
|
||||||
|
|
||||||
Config::Config( const po::variables_map& vm )
|
Config::Config( const po::variables_map& vm )
|
||||||
{
|
{
|
||||||
|
if ( vm.count( "id" ) > 0 )
|
||||||
|
m_cmd.Add( "id", Val( vm["id"].as<std::string>() ) ) ;
|
||||||
|
if ( vm.count( "secret" ) > 0 )
|
||||||
|
m_cmd.Add( "secret", Val( vm["secret"].as<std::string>() ) ) ;
|
||||||
m_cmd.Add( "new-rev", Val(vm.count("new-rev") > 0) ) ;
|
m_cmd.Add( "new-rev", Val(vm.count("new-rev") > 0) ) ;
|
||||||
m_cmd.Add( "force", Val(vm.count("force") > 0 ) ) ;
|
m_cmd.Add( "force", Val(vm.count("force") > 0 ) ) ;
|
||||||
m_cmd.Add( "path", Val(vm.count("path") > 0
|
m_cmd.Add( "path", Val(vm.count("path") > 0
|
||||||
|
@ -80,7 +84,7 @@ void Config::Save( )
|
||||||
|
|
||||||
void Config::Set( const std::string& key, const Val& value )
|
void Config::Set( const std::string& key, const Val& value )
|
||||||
{
|
{
|
||||||
m_file.Add( key, value ) ;
|
m_file.Set( key, value ) ;
|
||||||
}
|
}
|
||||||
|
|
||||||
Val Config::Get( const std::string& key ) const
|
Val Config::Get( const std::string& key ) const
|
||||||
|
|
|
@ -59,7 +59,7 @@ void Stat( const std::string& filename, DateTime *t, off64_t *size, FileType *ft
|
||||||
|
|
||||||
if ( t )
|
if ( t )
|
||||||
{
|
{
|
||||||
#if defined __APPLE__ && defined __DARWIN_64_BIT_INO_T
|
#if defined __NetBSD__ || ( defined __APPLE__ && defined __DARWIN_64_BIT_INO_T )
|
||||||
*t = DateTime( s.st_ctimespec.tv_sec, s.st_ctimespec.tv_nsec ) ;
|
*t = DateTime( s.st_ctimespec.tv_sec, s.st_ctimespec.tv_nsec ) ;
|
||||||
#else
|
#else
|
||||||
*t = DateTime( s.st_ctim.tv_sec, s.st_ctim.tv_nsec);
|
*t = DateTime( s.st_ctim.tv_sec, s.st_ctim.tv_nsec);
|
||||||
|
|
|
@ -31,6 +31,10 @@ class Path ;
|
||||||
|
|
||||||
enum FileType { FT_FILE = 1, FT_DIR = 2, FT_UNKNOWN = 3 } ;
|
enum FileType { FT_FILE = 1, FT_DIR = 2, FT_UNKNOWN = 3 } ;
|
||||||
|
|
||||||
|
#ifndef off64_t
|
||||||
|
#define off64_t off_t
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace os
|
namespace os
|
||||||
{
|
{
|
||||||
struct Error : virtual Exception {} ;
|
struct Error : virtual Exception {} ;
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
SET(GRIVE_SYNC_SH_BINARY "${CMAKE_INSTALL_PREFIX}/lib/grive/grive-sync.sh")
|
SET(GRIVE_SYNC_SH_BINARY "${CMAKE_INSTALL_FULL_LIBEXECDIR}/grive/grive-sync.sh")
|
||||||
|
|
||||||
CONFIGURE_FILE(grive-changes@.service.in grive-changes@.service @ONLY)
|
CONFIGURE_FILE(grive-changes@.service.in grive-changes@.service @ONLY)
|
||||||
CONFIGURE_FILE(grive-timer@.service.in grive-timer@.service @ONLY)
|
CONFIGURE_FILE(grive-timer@.service.in grive-timer@.service @ONLY)
|
||||||
|
|
||||||
install(
|
install(
|
||||||
FILES
|
FILES
|
||||||
|
grive@.service
|
||||||
${CMAKE_BINARY_DIR}/systemd/grive-changes@.service
|
${CMAKE_BINARY_DIR}/systemd/grive-changes@.service
|
||||||
${CMAKE_BINARY_DIR}/systemd/grive-timer@.service
|
${CMAKE_BINARY_DIR}/systemd/grive-timer@.service
|
||||||
DESTINATION
|
DESTINATION
|
||||||
|
@ -22,5 +23,5 @@ install(
|
||||||
PROGRAMS
|
PROGRAMS
|
||||||
grive-sync.sh
|
grive-sync.sh
|
||||||
DESTINATION
|
DESTINATION
|
||||||
lib/grive
|
${CMAKE_INSTALL_FULL_LIBEXECDIR}/grive
|
||||||
)
|
)
|
||||||
|
|
|
@ -15,7 +15,7 @@ cd ~
|
||||||
|
|
||||||
### ARGUMENT PARSING ###
|
### ARGUMENT PARSING ###
|
||||||
SCRIPT="${0}"
|
SCRIPT="${0}"
|
||||||
DIRECTORY=$(systemd-escape --unescape "$2")
|
DIRECTORY=$(systemd-escape --unescape -- "$2")
|
||||||
|
|
||||||
if [[ -z "$DIRECTORY" ]] || [[ ! -d "$DIRECTORY" ]] ; then
|
if [[ -z "$DIRECTORY" ]] || [[ ! -d "$DIRECTORY" ]] ; then
|
||||||
echo "Need a directory name in the current users home directory as second argument. Aborting."
|
echo "Need a directory name in the current users home directory as second argument. Aborting."
|
||||||
|
@ -62,39 +62,36 @@ unlock() { _lock u; } # drop a lock
|
||||||
|
|
||||||
sync_directory() {
|
sync_directory() {
|
||||||
_directory="${1}"
|
_directory="${1}"
|
||||||
|
|
||||||
|
reset_timer_and_exit() { echo "Retriggered google drive sync ('${_directory}')" && touch -m $LOCKFILE && exit; }
|
||||||
|
|
||||||
|
exlock_now || reset_timer_and_exit
|
||||||
|
|
||||||
if ping -c1 -W1 -q accounts.google.com >/dev/null 2>&1; then
|
if ping -c1 -W1 -q accounts.google.com >/dev/null 2>&1; then
|
||||||
true
|
true
|
||||||
# pass
|
# pass
|
||||||
else
|
else
|
||||||
echo "Google drive server not reachable..."
|
echo "Google drive server not reachable, NOT syncing..."
|
||||||
|
unlock
|
||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
reset_timer_and_exit() { echo "Retriggered google drive sync" && touch -m "$LOCKFILE" && exit; }
|
|
||||||
|
|
||||||
exlock_now || reset_timer_and_exit
|
|
||||||
|
|
||||||
TIME_AT_START=0
|
TIME_AT_START=0
|
||||||
TIME_AT_END=1
|
TIME_AT_END=1
|
||||||
while [[ "${TIME_AT_START}" -lt "${TIME_AT_END}" ]]; do
|
while [[ "${TIME_AT_START}" -lt "${TIME_AT_END}" ]]; do
|
||||||
echo "Syncing "${_directory}"..."
|
echo "Syncing '${_directory}'..."
|
||||||
TIME_AT_START="$(stat -c %Y "$LOCKFILE")"
|
TIME_AT_START="$(stat -c %Y "$LOCKFILE")"
|
||||||
# exclude symlinks from sync
|
|
||||||
cat "${_directory}"/.griveignore 2>/dev/null | sed '/#LINKS-EDIT_BEFORE_THIS$/,$d' > /tmp/.griveignore.base
|
|
||||||
cp /tmp/.griveignore.base "${_directory}"/.griveignore
|
|
||||||
rm /tmp/.griveignore.base
|
|
||||||
echo "#LINKS-EDIT_BEFORE_THIS" >> "${_directory}"/.griveignore
|
|
||||||
( cd "${_directory}" && find . -type l | sed 's/^.\///g'; ) >> "${_directory}"/.griveignore
|
|
||||||
grive -p "${_directory}" 2>&1 | grep -v -E "^Reading local directories$|^Reading remote server file list$|^Synchronizing files$|^Finished!$"
|
grive -p "${_directory}" 2>&1 | grep -v -E "^Reading local directories$|^Reading remote server file list$|^Synchronizing files$|^Finished!$"
|
||||||
TIME_AT_END="$(stat -c %Y "$LOCKFILE")"
|
TIME_AT_END="$(stat -c %Y "$LOCKFILE")"
|
||||||
echo "Sync of "${_directory}" done."
|
echo "Sync of '${_directory}' done."
|
||||||
done
|
done
|
||||||
|
|
||||||
# always exit ok, so that we never go into a wrong systemd state
|
# always exit ok, so that we never go into a wrong systemd state
|
||||||
|
unlock
|
||||||
exit 0
|
exit 0
|
||||||
}
|
}
|
||||||
|
|
||||||
### LISTEN TO DIRECTORY CHANGES ###
|
### LISTEN TO CHANGES IN DIRECTORY ###
|
||||||
|
|
||||||
|
|
||||||
listen_directory() {
|
listen_directory() {
|
||||||
|
@ -102,7 +99,7 @@ listen_directory() {
|
||||||
|
|
||||||
type inotifywait >/dev/null 2>&1 || { echo >&2 "I require inotifywait but it's not installed. Aborting."; exit 1; }
|
type inotifywait >/dev/null 2>&1 || { echo >&2 "I require inotifywait but it's not installed. Aborting."; exit 1; }
|
||||||
|
|
||||||
echo "Listening for changes in ~/"${_directory}""
|
echo "Listening for changes in '${_directory}'"
|
||||||
|
|
||||||
while true #run indefinitely
|
while true #run indefinitely
|
||||||
do
|
do
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
[Unit]
|
[Unit]
|
||||||
Description=Google drive sync
|
Description=Google drive sync (executed by timer unit)
|
||||||
After=network-online.target
|
After=network-online.target
|
||||||
|
|
||||||
[Service]
|
[Service]
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
[Unit]
|
||||||
|
Description=Google drive sync (main)
|
||||||
|
Requires=grive-timer@%i.timer grive-changes@%i.service
|
||||||
|
|
||||||
|
# dummy service
|
||||||
|
[Service]
|
||||||
|
Type=oneshot
|
||||||
|
ExecStart=/bin/true
|
||||||
|
# This service shall be considered active after start
|
||||||
|
RemainAfterExit=yes
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=default.target
|
Loading…
Reference in New Issue