Merge 'master' into PR and resolve conflicts

* Merge 'master' into PR and resolve conflicts
This commit is contained in:
abraunegg 2020-09-19 08:07:48 +10:00
commit 7e153e0ba3
20 changed files with 981 additions and 251 deletions

View file

@ -2,6 +2,35 @@
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
## 2.4.5 - 2020-08-13
### Fixed
* Fixed fish auto completions installation destination
## 2.4.4 - 2020-08-11
### Fixed
* Fix 'skip_dir' & 'skip_file' pattern matching to ensure correct matching is performed
* Fix 'skip_dir' & 'skip_file' so that each directive is only used against directories or files as requried in --monitor
* Fix client hand when attempting to sync a Unix pipe file
* Fix --single-directory & 'sync_list' performance
* Fix erroneous 'return' statements which could prematurely end processing all changes returned from OneDrive
* Fix segfault when attempting to perform a comparison on an inotify event when determining if event path is directory or file
* Fix handling of Shared Folders to ensure these are checked against 'skip_dir' entries
* Fix 'Skipping uploading this new file as parent path is not in the database' when uploading to a Personal Shared Folder
* Fix how available free space is tracked when uploading files to OneDrive and Shared Folders
* Fix --single-directory handling of parent path matching if path is being seen for first time
### Added
* Added Fish auto completions
### Updated
* Increase maximum individual file size to 100GB due to Microsoft file limit increase
* Update Docker build files and align version of compiler across all Docker builds
* Update Docker documentation
* Update NixOS build information
* Update the 'Processing XXXX' output to display the full path
* Update logging output when a sync starts and completes when using --monitor
* Update Office 365 / SharePoint site search query and response if query return zero match
## 2.4.3 - 2020-06-29
### Fixed
* Check if symbolic link is relative to location path

View file

@ -28,6 +28,7 @@ notify_LIBS = @notify_LIBS@
COMPLETIONS = @COMPLETIONS@
BASH_COMPLETION_DIR = @BASH_COMPLETION_DIR@
ZSH_COMPLETION_DIR = @ZSH_COMPLETION_DIR@
FISH_COMPLETION_DIR = @FISH_COMPLETION_DIR@
DEBUG = @DEBUG@
DC = @DC@
@ -127,6 +128,7 @@ endif
ifeq ($(COMPLETIONS),yes)
$(INSTALL) -D -m 644 contrib/completions/complete.zsh $(DESTDIR)$(ZSH_COMPLETION_DIR)/_onedrive
$(INSTALL) -D -m 644 contrib/completions/complete.bash $(DESTDIR)$(BASH_COMPLETION_DIR)/onedrive
$(INSTALL) -D -m 644 contrib/completions/complete.fish $(DESTDIR)$(FISH_COMPLETION_DIR)/onedrive.fish
endif
@ -151,6 +153,7 @@ endif
ifeq ($(COMPLETIONS),yes)
rm -f $(DESTDIR)$(ZSH_COMPLETION_DIR)/_onedrive
rm -f $(DESTDIR)$(BASH_COMPLETION_DIR)/onedrive
rm -f $(DESTDIR)$(FISH_COMPLETION_DIR)/onedrive.fish
endif

View file

@ -7,7 +7,7 @@
A free Microsoft OneDrive Client which supports OneDrive Personal, OneDrive for Business, OneDrive for Office365 and Sharepoint.
This powerful and highly configurable client can run on all major Linux distributions, as a Docker container and on FreeBSD. It supports one-way and two-way sync capabilities and securely connects to Microsoft OneDrive services.
This powerful and highly configurable client can run on all major Linux distributions, FreeBSD, or as a Docker container. It supports one-way and two-way sync capabilities and securely connects to Microsoft OneDrive services.
This client is a 'fork' of the [skilion](https://github.com/skilion/onedrive) client which was abandoned in 2018.
@ -25,26 +25,10 @@ This client is a 'fork' of the [skilion](https://github.com/skilion/onedrive) cl
* Support for National cloud deployments (Microsoft Cloud for US Government, Microsoft Cloud Germany, Azure and Office 365 operated by 21Vianet in China)
## What's missing
* While local changes are uploaded right away, remote changes are delayed until next sync when using --monitor
* No GUI
## Building and Installation
See [docs/INSTALL.md](https://github.com/abraunegg/onedrive/blob/master/docs/INSTALL.md)
## Configuration and Usage
See [docs/USAGE.md](https://github.com/abraunegg/onedrive/blob/master/docs/USAGE.md)
## Docker support
See [docs/Docker.md](https://github.com/abraunegg/onedrive/blob/master/docs/Docker.md)
## OneDrive Business Shared Folders
See [docs/BusinessSharedFolders.md](https://github.com/abraunegg/onedrive/blob/master/docs/BusinessSharedFolders.md)
## SharePoint / Office 365 Shared Libraries (Business or Education)
See [docs/Office365.md](https://github.com/abraunegg/onedrive/blob/master/docs/Office365.md)
## National Cloud support
See [docs/national-cloud-deployments.md](https://github.com/abraunegg/onedrive/blob/master/docs/national-cloud-deployments.md)
* While local changes are uploaded right away, remote changes are delayed until next automated sync cycle when using --monitor
* Ability to encrypt/decrpyt files on-the-fly when uploading/downloading files from OneDrive
* Support for Windows 'On-Demand' functionality so file is only downloaded when accessed locally
* A GUI for configuration management
## Reporting issues
If you encounter any bugs you can report them here on Github. Before filing an issue be sure to:
@ -56,3 +40,22 @@ If you encounter any bugs you can report them here on Github. Before filing an i
## Known issues
See [docs/known-issues.md](https://github.com/abraunegg/onedrive/blob/master/docs/known-issues.md)
## Documentation and Configuration Assistance
### Building and Installation
See [docs/INSTALL.md](https://github.com/abraunegg/onedrive/blob/master/docs/INSTALL.md)
### Configuration and Usage
See [docs/USAGE.md](https://github.com/abraunegg/onedrive/blob/master/docs/USAGE.md)
### Configure OneDrive Business Shared Folders
See [docs/BusinessSharedFolders.md](https://github.com/abraunegg/onedrive/blob/master/docs/BusinessSharedFolders.md)
### Configure SharePoint / Office 365 Shared Libraries (Business or Education)
See [docs/Office365.md](https://github.com/abraunegg/onedrive/blob/master/docs/Office365.md)
### Configure National Cloud support
See [docs/national-cloud-deployments.md](https://github.com/abraunegg/onedrive/blob/master/docs/national-cloud-deployments.md)
### Docker support
See [docs/Docker.md](https://github.com/abraunegg/onedrive/blob/master/docs/Docker.md)

43
configure vendored
View file

@ -1,6 +1,6 @@
#! /bin/sh
# Guess values for system-dependent variables and create Makefiles.
# Generated by GNU Autoconf 2.69 for onedrive v2.4.4-dev.
# Generated by GNU Autoconf 2.69 for onedrive v2.4.6-dev.
#
# Report bugs to <https://github.com/abraunegg/onedrive>.
#
@ -579,8 +579,8 @@ MAKEFLAGS=
# Identity of this package.
PACKAGE_NAME='onedrive'
PACKAGE_TARNAME='onedrive'
PACKAGE_VERSION='v2.4.4-dev'
PACKAGE_STRING='onedrive v2.4.4-dev'
PACKAGE_VERSION='v2.4.6-dev'
PACKAGE_STRING='onedrive v2.4.6-dev'
PACKAGE_BUGREPORT='https://github.com/abraunegg/onedrive'
PACKAGE_URL=''
@ -588,6 +588,7 @@ ac_unique_file="src/main.d"
ac_subst_vars='LTLIBOBJS
LIBOBJS
DEBUG
FISH_COMPLETION_DIR
ZSH_COMPLETION_DIR
BASH_COMPLETION_DIR
bashcompdir
@ -660,6 +661,7 @@ enable_notifications
enable_completions
with_bash_completion_dir
with_zsh_completion_dir
with_fish_completion_dir
enable_debug
'
ac_precious_vars='build_alias
@ -1217,7 +1219,7 @@ if test "$ac_init_help" = "long"; then
# Omit some internal or obsolete options to make the list less imposing.
# This message is too long to be a string in the A/UX 3.1 sh.
cat <<_ACEOF
\`configure' configures onedrive v2.4.4-dev to adapt to many kinds of systems.
\`configure' configures onedrive v2.4.6-dev to adapt to many kinds of systems.
Usage: $0 [OPTION]... [VAR=VALUE]...
@ -1278,7 +1280,7 @@ fi
if test -n "$ac_init_help"; then
case $ac_init_help in
short | recursive ) echo "Configuration of onedrive v2.4.4-dev:";;
short | recursive ) echo "Configuration of onedrive v2.4.6-dev:";;
esac
cat <<\_ACEOF
@ -1289,7 +1291,7 @@ Optional Features:
--disable-version-check Disable checks of compiler version during configure
time
--enable-notifications Enable desktop notifications via libnotify
--enable-completions Install shell completions for bash and zsh
--enable-completions Install shell completions for bash, zsh, and fish
--enable-debug Pass debug option to the compiler
Optional Packages:
@ -1303,6 +1305,8 @@ Optional Packages:
Directory for bash completion files
--with-zsh-completion-dir=DIR
Directory for zsh completion files
--with-fish-completion-dir=DIR
Directory for fish completion files
Some influential environment variables:
DC D compiler executable
@ -1389,7 +1393,7 @@ fi
test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then
cat <<\_ACEOF
onedrive configure v2.4.4-dev
onedrive configure v2.4.6-dev
generated by GNU Autoconf 2.69
Copyright (C) 2012 Free Software Foundation, Inc.
@ -1406,7 +1410,7 @@ cat >config.log <<_ACEOF
This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake.
It was created by onedrive $as_me v2.4.4-dev, which was
It was created by onedrive $as_me v2.4.6-dev, which was
generated by GNU Autoconf 2.69. Invocation command line was
$ $0 $@
@ -2158,7 +2162,7 @@ fi
PACKAGE_DATE="June 2020"
PACKAGE_DATE="August 2020"
@ -2579,6 +2583,23 @@ fi
ZSH_COMPLETION_DIR=$with_zsh_completion_dir
# Check whether --with-fish-completion-dir was given.
if test "${with_fish_completion_dir+set}" = set; then :
withval=$with_fish_completion_dir;
else
with_fish_completion_dir=auto
fi
if test "x$with_fish_completion_dir" = "xyes" -o "x$with_fish_completion_dir" = "xauto"; then :
with_fish_completion_dir="/usr/local/share/fish/completions"
fi
FISH_COMPLETION_DIR=$with_fish_completion_dir
fi
# Check whether --enable-debug was given.
@ -3138,7 +3159,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
# report actual input values of CONFIG_FILES etc. instead of their
# values after options handling.
ac_log="
This file was extended by onedrive $as_me v2.4.4-dev, which was
This file was extended by onedrive $as_me v2.4.6-dev, which was
generated by GNU Autoconf 2.69. Invocation command line was
CONFIG_FILES = $CONFIG_FILES
@ -3191,7 +3212,7 @@ _ACEOF
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
ac_cs_version="\\
onedrive config.status v2.4.4-dev
onedrive config.status v2.4.6-dev
configured by $0, generated by GNU Autoconf 2.69,
with options \\"\$ac_cs_config\\"

View file

@ -9,7 +9,7 @@ dnl - commit the changed files (configure.ac, configure)
dnl - tag the release
AC_PREREQ([2.69])
AC_INIT([onedrive],[v2.4.4-dev], [https://github.com/abraunegg/onedrive], [onedrive])
AC_INIT([onedrive],[v2.4.6-dev], [https://github.com/abraunegg/onedrive], [onedrive])
AC_CONFIG_SRCDIR([src/main.d])
@ -228,7 +228,7 @@ dnl
dnl Completion support
dnl First determine whether completions are requested, pass that to Makefile
AC_ARG_ENABLE([completions],
AS_HELP_STRING([--enable-completions], [Install shell completions for bash and zsh]))
AS_HELP_STRING([--enable-completions], [Install shell completions for bash, zsh, and fish]))
AS_IF([test "x$enable_completions" = "xyes"], [enable_completions=yes], [enable_completions=no])
@ -258,6 +258,16 @@ AS_IF([test "x$enable_completions" = "xyes"],[
with_zsh_completion_dir="/usr/local/share/zsh/site-functions"
])
AC_SUBST([ZSH_COMPLETION_DIR], $with_zsh_completion_dir)
AC_ARG_WITH([fish-completion-dir],
[AS_HELP_STRING([--with-fish-completion-dir=DIR], [Directory for fish completion files])],,
[with_fish_completion_dir=auto])
AS_IF([test "x$with_fish_completion_dir" = "xyes" -o "x$with_fish_completion_dir" = "xauto"],
[
with_fish_completion_dir="/usr/local/share/fish/completions"
])
AC_SUBST([FISH_COMPLETION_DIR], $with_fish_completion_dir)
])
dnl

View file

@ -0,0 +1,35 @@
# FISH completions for OneDrive Linux Client
# License: GPLv3+ (as with the rest of the OneDrive Linux client project)
complete -c onedrive -f
complete -c onedrive -l check-for-nomount -d 'Check for the presence of .nosync in the syncdir root. If found, do not perform sync.'
complete -c onedrive -l check-for-nosync -d 'Check for the presence of .nosync in each directory. If found, skip directory from sync.'
complete -c onedrive -l create-directory -d 'Create a directory on OneDrive - no sync will be performed.'
complete -c onedrive -l debug-https -d 'Debug OneDrive HTTPS communication.'
complete -c onedrive -l disable-notifications -d 'Do not use desktop notifications in monitor mode.'
complete -c onedrive -l disable-upload-validation -d 'Disable upload validation when uploading to OneDrive.'
complete -c onedrive -l display-config -d 'Display what options the client will use as currently configured - no sync will be performed.'
complete -c onedrive -l display-sync-status -d 'Display the sync status of the client - no sync will be performed.'
complete -c onedrive -l download-only -d 'Only download remote changes.'
complete -c onedrive -l dry-run -d 'Perform a trial sync with no changes made.'
complete -c onedrive -l enable-logging -d 'Enable client activity to a separate log file.'
complete -c onedrive -l force-http-1.1 -d 'Force the use of HTTP 1.1 for all operations.'
complete -c onedrive -l force-http-2 -d 'Force the use of HTTP 2 for all operations.'
complete -c onedrive -l get-O365-drive-id -d 'Query and return the Office 365 Drive ID for a given Office 365 SharePoint Shared Library.'
complete -c onedrive -s h -l help -d 'Print help information.'
complete -c onedrive -l local-first -d 'Synchronize from the local directory source first, before downloading changes from OneDrive.'
complete -c onedrive -l logout -d 'Logout the current user.'
complete -c onedrive -n "not __fish_seen_subcommand_from --synchronize" -a "-m --monitor" -d 'Keep monitoring for local and remote changes.'
complete -c onedrive -l no-remote-delete -d 'Do not delete local file deletes from OneDrive when using --upload-only.'
complete -c onedrive -l print-token -d 'Print the access token, useful for debugging.'
complete -c onedrive -l remote-directory -d 'Remove a directory on OneDrive - no sync will be performed.'
complete -c onedrive -l resync -d 'Forget the last saved state, perform a full sync.'
complete -c onedrive -l single-directory -d 'Specify a single local directory within the OneDrive root to sync.'
complete -c onedrive -l skip-dot-files -d 'Skip dot files and folders from syncing.'
complete -c onedrive -l skip-symlinks -d 'Skip syncing of symlinks.'
complete -c onedrive -l source-directory -d 'Source directory to rename or move on OneDrive - no sync will be performed.'
complete -c onedrive -n "not __fish_seen_subcommand_from --monitor; and not __fish_seen_subcommand_from -m" -l synchronize -d 'Perform a synchronization.'
complete -c onedrive -l upload-only -d 'Only upload to OneDrive, do not sync changes from OneDrive locally'
complete -c onedrive -s v -l verbose -d 'Print more details, useful for debugging (repeat for extra debugging).'
complete -c onedrive -l version -d 'Print the version and exit.'

View file

@ -6,7 +6,7 @@
%endif
Name: onedrive
Version: 2.4.3
Version: 2.4.5
Release: 1%{?dist}
Summary: Microsoft OneDrive Client
Group: System Environment/Network

View file

@ -11,7 +11,7 @@ This container offers simple monitoring-mode service for 'Free Client for OneDri
### 1. Pull the image
```bash
docker pull driveone/onedrive
docker pull driveone/onedrive:latest
```
**NOTE:** SELinux context needs to be configured or disabled for Docker, to be able to write to OneDrive host directory.
@ -34,11 +34,12 @@ The second docker volume is for your data folder and is created in the next step
### 3. First run
Onedrive needs to be authorized with your Microsoft account. This is achieved by running docker in interactive mode. Run the docker image with the two commands below and **make sure to change `onedriveDir` to the onedrive data directory on your filesystem (e.g. `"/home/abraunegg/OneDrive"`)**
Onedrive needs to be authorized with your Microsoft account. This is achieved by running docker in interactive mode. Run the docker image with the two commands below and **make sure to change `onedriveDir` to the onedrive data directory on your filesystem (e.g. `"/home/abraunegg/OneDrive"`)**.
Additionally, the user id and group id should be added to remove any potential user conflicts, denoted by the environment variables `${ONEDRIVE_UID}` and `${ONEDRIVE_GID}`.
```bash
onedriveDir="${HOME}/OneDrive"
docker run -it --restart unless-stopped --name onedrive -v onedrive_conf:/onedrive/conf -v "${onedriveDir}:/onedrive/data" driveone/onedrive
docker run -it --name onedrive -v onedrive_conf:/onedrive/conf -v "${onedriveDir}:/onedrive/data" -e "ONEDRIVE_UID:${ONEDRIVE_UID}" -e "ONEDRIVE_GID:${ONEDRIVE_GID}" driveone/onedrive:latest
```
- You will be asked to open a specific link using your web browser
@ -81,7 +82,29 @@ docker rm -f onedrive
```
## Advanced Setup
### 5. Edit the config
### 5. Docker-compose
Also supports docker-compose schemas > 3.
In the following example it is assumed you have a `onedriveDir` environment variable and a `onedrive_conf` volume.
However, you can also use bind mounts for the configuration folder, e.g. `export ONEDRIVE_CONF="${HOME}/OneDriveConfig"`.
```
version: "3"
services:
onedrive:
image: driveone/onedrive:latest
restart: unless-stopped
environment:
- ONEDRIVE_UID=${PUID}
- ONEDRIVE_GID=${PGID}
volumes:
- onedrive_conf:/onedrive/conf
- ${onedriveDir}:/onedrive/data
```
Note that you still have to perform step 3: First Run.
### 6. Edit the config
Onedrive should run in default configuration, however you can change your configuration by placing a custom config file in the `onedrive_conf` docker volume. First download the default config from [here](https://raw.githubusercontent.com/abraunegg/onedrive/master/config)
Then put it into your onedrive_conf volume path, which can be found with:
@ -94,14 +117,14 @@ Or you can map your own config folder to the config volume. Make sure to copy al
The detailed document for the config can be found here: [additional-configuration](https://github.com/abraunegg/onedrive#additional-configuration)
### 6. Sync multiple accounts
### 7. Sync multiple accounts
There are many ways to do this, the easiest is probably to
1. Create a second docker config volume (replace `Work` with your desired name): `docker volume create onedrive_conf_Work`
2. And start a second docker monitor container (again replace `Work` with your desired name):
```
onedriveDirWork="/home/abraunegg/OneDriveWork"
docker run -it --restart unless-stopped --name onedrive_Work -v onedrive_conf_Work:/onedrive/conf -v "${onedriveDirWork}:/onedrive/data" driveone/onedrive
docker run -it --restart unless-stopped --name onedrive_Work -v onedrive_conf_Work:/onedrive/conf -v "${onedriveDirWork}:/onedrive/data" driveone/onedrive:latest
```
## Run or update with one script
@ -113,10 +136,10 @@ If you are experienced with docker and onedrive, you can use the following scrip
onedriveDir="${HOME}/OneDrive"
firstRun='-d'
docker pull driveone/onedrive
docker pull driveone/onedrive:latest
docker inspect onedrive_conf > /dev/null || { docker volume create onedrive_conf; firstRun='-it'; }
docker inspect onedrive > /dev/null && docker rm -f onedrive
docker run $firstRun --restart unless-stopped --name onedrive -v onedrive_conf:/onedrive/conf -v "${onedriveDir}:/onedrive/data" driveone/onedrive
docker run $firstRun --restart unless-stopped --name onedrive -v onedrive_conf:/onedrive/conf -v "${onedriveDir}:/onedrive/data" driveone/onedrive:latest
```
@ -134,19 +157,19 @@ docker run $firstRun --restart unless-stopped --name onedrive -v onedrive_conf:/
### Usage Examples
**Verbose Output:**
```bash
docker container run -e ONEDRIVE_VERBOSE=1 -v onedrive_conf:/onedrive/conf -v "${onedriveDir}:/onedrive/data" driveone/onedrive
docker container run -e ONEDRIVE_VERBOSE=1 -v onedrive_conf:/onedrive/conf -v "${onedriveDir}:/onedrive/data" driveone/onedrive:latest
```
**Debug Output:**
```bash
docker container run -e ONEDRIVE_DEBUG=1 -v onedrive_conf:/onedrive/conf -v "${onedriveDir}:/onedrive/data" driveone/onedrive
docker container run -e ONEDRIVE_DEBUG=1 -v onedrive_conf:/onedrive/conf -v "${onedriveDir}:/onedrive/data" driveone/onedrive:latest
```
**Perform a --resync:**
```bash
docker container run -e ONEDRIVE_RESYNC=1 -v onedrive_conf:/onedrive/conf -v "${onedriveDir}:/onedrive/data" driveone/onedrive
docker container run -e ONEDRIVE_RESYNC=1 -v onedrive_conf:/onedrive/conf -v "${onedriveDir}:/onedrive/data" driveone/onedrive:latest
```
**Perform a --resync and --verbose:**
```bash
docker container run -e ONEDRIVE_RESYNC=1 -e ONEDRIVE_VERBOSE=1 -v onedrive_conf:/onedrive/conf -v "${onedriveDir}:/onedrive/data" driveone/onedrive
docker container run -e ONEDRIVE_RESYNC=1 -e ONEDRIVE_VERBOSE=1 -v onedrive_conf:/onedrive/conf -v "${onedriveDir}:/onedrive/data" driveone/onedrive:latest
```
## Build instructions

View file

@ -6,8 +6,8 @@ This project has been packaged for the following Linux distributions:
* Arch Linux, available from AUR as [onedrive-abraunegg](https://aur.archlinux.org/packages/onedrive-abraunegg/)
* Debian, available from the package repository as [onedrive](https://packages.debian.org/sid/net/onedrive)
* Fedora, available via package repositories as [onedrive](https://koji.fedoraproject.org/koji/packageinfo?packageID=26044)
* NixOS, available on unstable channel (and stable since 20.03). Use package `onedrive` either by adding it to `configuration.nix` or by using the command `nix-env -iA <channel name>.onedrive`. This does not install a service. There is a [PR](https://github.com/NixOS/nixpkgs/pull/77734) (which needs work) which has code which can be used to install a service. See documentation in the same PR.
* openSUSE, available for Tumbleweed as [onedrive](https://software.opensuse.org/package/onedrive) - just install using: `zypper in onedrive`
* NixOS, use package `onedrive` either by adding it to `configuration.nix` or by using the command `nix-env -iA <channel name>.onedrive`. This does not install a service. To install a service, use unstable channel (will stabilize in 20.09) and add `services.onedrive.enable=true` in `configuration.nix`. You can also add a custom package using the `services.onedrive.package` option (recommended since package lags upstream). Enabling the service installs a default package too (based on the channel). You can also add multiple onedrive accounts trivially, see [documentation](https://github.com/NixOS/nixpkgs/pull/77734#issuecomment-575874225)`.
* openSUSE, available for Tumbleweed as [onedrive](https://software.opensuse.org/package/onedrive)
* Slackware, available from the slackbuilds.org repository as [onedrive](https://slackbuilds.org/repository/14.2/network/onedrive/)
* Solus, available from the package repository as [onedrive](https://dev.getsol.us/search/query/FB7PIf1jG9Z9/#R)
* Ubuntu, available as a package from the following PPA [onedrive](https://launchpad.net/~yann1ck/+archive/ubuntu/onedrive)
@ -16,16 +16,27 @@ This project has been packaged for the following Linux distributions:
Distribution packages may be of an older release when compared to the latest release that is [available](https://github.com/abraunegg/onedrive/releases). If a package is out of date, please contact the package maintainer for resolution.
#### Important information for Ubuntu users:
Whilst there are [onedrive](https://packages.ubuntu.com/search?keywords=onedrive&searchon=names&suite=all&section=all) packages available for Ubuntu, do not install 'onedrive' from these packages. These packages are out of date and should not be used. If you wish to use a package, use the PPA listed above.
Whilst there are [onedrive](https://packages.ubuntu.com/search?keywords=onedrive&searchon=names&suite=all&section=all) packages available for Ubuntu, do not install 'onedrive' from these packages via `apt install onedrive`. These packages are out-of-date and should not be used. If you wish to use a package, it is highly recommended that you utilise the PPA listed above or build from source using the instructions below for Ubuntu and those distributions (such as Lubuntu) which are derived from Ubuntu.
## Build Requirements
* Build environment must have at least 1GB of memory & 1GB swap space
* [libcurl](http://curl.haxx.se/libcurl/)
* [SQLite 3](https://www.sqlite.org/) >= 3.7.15
* [Digital Mars D Compiler (DMD)](http://dlang.org/download.html)
* [Digital Mars D Compiler (DMD)](http://dlang.org/download.html) or [LDC the LLVM-based D Compiler](https://github.com/ldc-developers/ldc)
**Note:** DMD version >= 2.083.1 or LDC version >= 1.12.0 is required to compile this application
### Example for installing DMD Compiler
```text
curl -fsS https://dlang.org/install.sh | bash -s dmd
```
### Example for installing LDC Compiler
```text
curl -fsS https://dlang.org/install.sh | bash -s ldc
```
## Distribution Package Dependencies
### Dependencies: Ubuntu 16.x - i386 / i686 (less than 1GB Memory)
**Important:** Build environment must have at least 512 of memory & 1GB swap space
@ -292,6 +303,7 @@ as far as possible automatically, but can be overridden by passing
### Building using a different compiler (for example [LDC](https://wiki.dlang.org/LDC))
#### ARMHF Architecture
**Note:** Build environment must have at least 1GB of memory & 1GB swap space. Check with `swapon -s`
```text
git clone https://github.com/abraunegg/onedrive.git
cd onedrive
@ -301,6 +313,7 @@ sudo make install
```
#### ARM64 Architecture
**Note:** Build environment must have at least 1GB of memory & 1GB swap space. Check with `swapon -s`
```text
git clone https://github.com/abraunegg/onedrive.git
cd onedrive

View file

@ -340,6 +340,17 @@ Patterns are case insensitive. `*` and `?` [wildcards characters](https://techne
**Important:** Entries under `skip_dir` are relative to your `sync_dir` path.
**Note:** The `skip_dir` can be specified multiple times, for example:
```text
skip_dir = "SomeDir|OtherDir|ThisDir|ThatDir"
skip_dir = "/Path/To/A/Directory"
skip_dir = "/Another/Path/To/Different/Directory"
```
This will be interpreted the same as:
```text
skip_dir = "SomeDir|OtherDir|ThisDir|ThatDir|/Path/To/A/Directory|/Another/Path/To/Different/Directory"
```
**Note:** After changing `skip_dir`, you must perform a full re-synchronization by adding `--resync` to your existing command line - for example: `onedrive --synchronize --resync`
#### skip_file
@ -368,6 +379,17 @@ By default, the following files will be skipped:
**Important:** Do not use a skip_file entry of `.*` as this will prevent correct searching of local changes to process.
**Note:** The `skip_file` can be specified multiple times, for example:
```text
skip_file = "~*|.~*|*.tmp|*.swp"
skip_file = "*.blah"
skip_file = "never_sync.file"
```
This will be interpreted the same as:
```text
skip_file = "~*|.~*|*.tmp|*.swp|*.blah|never_sync.file"
```
**Note:** after changing `skip_file`, you must perform a full re-synchronization by adding `--resync` to your existing command line - for example: `onedrive --synchronize --resync`
#### skip_dotfiles
@ -421,20 +443,32 @@ Each line of the file represents a relative path from your `sync_dir`. All files
Here is an example of `sync_list`:
```text
# sync_list supports comments
# Exclude my Backup folder
# Include my Backup folder
Backup
# Exclude this single document
# Include Documents folder
Documents/
# Exclude temp folders under Documents
!Documents/temp*
# Include all PDF documents
Documents/*.pdf
# Include this single document
Documents/latest_report.docx
# Exclude all Work/Project directories
# Include all Work/Project directories
Work/Project*
notes.txt
# Exclude /Blender in the ~OneDrive root but not if elsewhere
# Include /Blender in the ~OneDrive root but not if elsewhere
/Blender
# Include these names if they match any file or folder
Cinema Soc
Codes
Textbooks
Year 2
```
The following are supported for pattern matching and exclusion rules:
* Use the `*` to wildcard select any characters to match for the item to be included
* Use either `!` or `-` characters at the start of the line to exclude an otherwise included item
**Note:** after changing the sync_list, you must perform a full re-synchronization by adding `--resync` to your existing command line - for example: `onedrive --synchronize --resync`
### How to 'skip' directories from syncing?
@ -595,6 +629,8 @@ onedrive --monitor --verbose --confdir="~/.config/onedriveWork" &
* `--monitor` keeps the application running and monitoring for changes both local and remote
* `&` puts the application in background and leaves the terminal interactive
**Important:** For each configuration, change the 'sync_dir' to a new value, unique for each specific configuration. Leaving this at the default of `sync_dir = "~/OneDrive"` will cause all data from both accounts to be synced to the same folder, then to each other.
### Automatic syncing of both OneDrive accounts
In order to automatically start syncing your OneDrive accounts, you will need to create a service file for each account. From the applicable 'user systemd folder':
* RHEL / CentOS: `/usr/lib/systemd/system`
@ -686,6 +722,8 @@ Options:
Set the directory used to store the configuration files
--create-directory ARG
Create a directory on OneDrive - no sync will be performed.
--create-share-link ARG
Create a shareable link for an existing file on OneDrive
--debug-https
Debug OneDrive HTTPS communication.
--destination-directory ARG

View file

@ -44,6 +44,9 @@ Set the directory used to store the configuration files
\fB\-\-create\-directory\fP ARG
Create a directory on OneDrive \- no sync will be performed.
.TP
\fB\-\-create\-share\-link\fP ARG
Create a shareable link for an existing file on OneDrive
.TP
\fB\-\-debug\-https\fP
Debug OneDrive HTTPS communication.
.br

View file

@ -249,6 +249,7 @@ final class Config
{
// Add additional options that are NOT configurable via config file
stringValues["create_directory"] = "";
stringValues["create_share_link"] = "";
stringValues["destination_directory"] = "";
stringValues["get_file_link"] = "";
stringValues["get_o365_drive_id"] = "";
@ -293,6 +294,9 @@ final class Config
"create-directory",
"Create a directory on OneDrive - no sync will be performed.",
&stringValues["create_directory"],
"create-share-link",
"Create a shareable link for an existing file on OneDrive",
&stringValues["create_share_link"],
"debug-https",
"Debug OneDrive HTTPS communication.",
&boolValues["debug_https"],
@ -540,8 +544,29 @@ final class Config
// --skip-file ARG
// --skip-dir ARG
if (key == "sync_dir") configFileSyncDir = c.front.dup;
if (key == "skip_file") configFileSkipFile = c.front.dup;
if (key == "skip_dir") configFileSkipDir = c.front.dup;
if (key == "skip_file") {
// Handle multiple entries of skip_file
if (configFileSkipFile.empty) {
// currently no entry exists
configFileSkipFile = c.front.dup;
} else {
// add to existing entry
configFileSkipFile = configFileSkipFile ~ "|" ~ to!string(c.front.dup);
setValueString("skip_file", configFileSkipFile);
}
}
if (key == "skip_dir") {
// Handle multiple entries of skip_dir
if (configFileSkipDir.empty) {
// currently no entry exists
configFileSkipDir = c.front.dup;
} else {
// add to existing entry
configFileSkipDir = configFileSkipDir ~ "|" ~ to!string(c.front.dup);
setValueString("skip_dir", configFileSkipDir);
}
}
// Azure AD Configuration
if (key == "azure_ad_endpoint") {
string azureConfigValue = c.front.dup;
@ -591,7 +616,9 @@ void outputLongHelp(Option[] opt)
auto argsNeedingOptions = [
"--confdir",
"--create-directory",
"--create-share-link",
"--destination-directory",
"--get-file-link",
"--get-O365-drive-id",
"--log-dir",
"--min-notify-changes",

View file

@ -248,7 +248,7 @@ final class ItemDatabase
}
// same as selectByPath() but it does not traverse remote folders
bool selectByPathWithRemote(const(char)[] path, string rootDriveId, out Item item)
bool selectByPathWithoutRemote(const(char)[] path, string rootDriveId, out Item item)
{
Item currItem = { driveId: rootDriveId };

View file

@ -565,7 +565,7 @@ int main(string[] args)
// create-directory, remove-directory, source-directory, destination-directory
// these are activities that dont perform a sync, so to not generate an error message for these items either
if (((cfg.getValueString("create_directory") != "") || (cfg.getValueString("remove_directory") != "")) || ((cfg.getValueString("source_directory") != "") && (cfg.getValueString("destination_directory") != "")) || (cfg.getValueString("get_file_link") != "") || (cfg.getValueString("get_o365_drive_id") != "") || cfg.getValueBool("display_sync_status") || cfg.getValueBool("list_business_shared_folders")) {
if (((cfg.getValueString("create_directory") != "") || (cfg.getValueString("remove_directory") != "")) || ((cfg.getValueString("source_directory") != "") && (cfg.getValueString("destination_directory") != "")) || (cfg.getValueString("get_file_link") != "") || (cfg.getValueString("create_share_link") != "") || (cfg.getValueString("get_o365_drive_id") != "") || cfg.getValueBool("display_sync_status") || cfg.getValueBool("list_business_shared_folders")) {
performSyncOK = true;
}
@ -700,8 +700,8 @@ int main(string[] args)
// Use exit scopes to shutdown API
return EXIT_FAILURE;
} else {
if (cfg.getValueString("get_file_link") == "") {
// Print out that we are initializing the engine only if we are not grabbing the file link
if ((cfg.getValueString("get_file_link") == "") && (cfg.getValueString("create_share_link") == "")) {
// Print out that we are initializing the engine only if we are not grabbing the file link or creating a shareable link
log.logAndNotify("Initializing the Synchronization Engine ...");
}
}
@ -790,8 +790,18 @@ int main(string[] args)
return EXIT_SUCCESS;
}
// Are we createing an anonymous read-only shareable link for an existing file on OneDrive?
if (cfg.getValueString("create_share_link") != "") {
// Query OneDrive for the file, and if valid, create a shareable link for the file
sync.createShareableLinkForFile(cfg.getValueString("create_share_link"));
// Exit application
// Use exit scopes to shutdown API
return EXIT_SUCCESS;
}
// Are we obtaining the URL path for a synced file?
if (cfg.getValueString("get_file_link") != "") {
// Query OneDrive for the file link
sync.queryOneDriveForFileURL(cfg.getValueString("get_file_link"), syncDir);
// Exit application
// Use exit scopes to shutdown API
@ -846,10 +856,10 @@ int main(string[] args)
if (cfg.getValueString("single_directory") != "") {
// Does the directory we want to sync actually exist?
if (!exists(cfg.getValueString("single_directory"))) {
// the requested directory does not exist ..
log.logAndNotify("ERROR: The requested local directory does not exist. Please check ~/OneDrive/ for requested path");
// Use exit scopes to shutdown API
return EXIT_FAILURE;
// The requested path to use with --single-directory does not exist locally within the configured 'sync_dir'
log.logAndNotify("WARNING: The requested path for --single-directory does not exist locally. Creating requested path within ", syncDir);
// Make the required path locally
mkdirRecurse(cfg.getValueString("single_directory"));
}
}
// perform a --synchronize sync
@ -1029,7 +1039,7 @@ int main(string[] args)
}
try {
// perform a --monitor sync
if (logMonitorCounter == logInterval) log.log("Starting a sync with OneDrive");
if ((cfg.getValueLong("verbose") > 0) || (logMonitorCounter == logInterval)) log.log("Starting a sync with OneDrive");
performSync(sync, cfg.getValueString("single_directory"), cfg.getValueBool("download_only"), cfg.getValueBool("local_first"), cfg.getValueBool("upload_only"), (logMonitorCounter == logInterval ? MONITOR_LOG_QUIET : MONITOR_LOG_SILENT), fullScanRequired, syncListConfiguredFullScanOverride, displaySyncOptions, cfg.getValueBool("monitor"), m);
if (!cfg.getValueBool("download_only")) {
// discard all events that may have been generated by the sync that have not already been handled
@ -1040,7 +1050,7 @@ int main(string[] args)
log.error("ERROR: The following inotify error was generated: ", e.msg);
}
}
if (logMonitorCounter == logInterval) log.log("Sync with OneDrive is complete");
if ((cfg.getValueLong("verbose") > 0) || (logMonitorCounter == logInterval)) log.log("Sync with OneDrive is complete");
} catch (CurlException e) {
// we already tried three times in the performSync routine
// if we still have problems, then the sync handle might have

View file

@ -84,19 +84,27 @@ final class Monitor
return;
}
// skip monitoring any filtered items
// Skip the monitoring of any user filtered items
if (dirname != ".") {
// is the directory name a match to a skip_dir entry?
if (selectiveSync.isDirNameExcluded(dirname.strip('.').strip('/'))) {
// dont add a watch for this item
log.vdebug("Skipping monitoring due to skip_dir match: ", dirname);
return;
// Is the directory name a match to a skip_dir entry?
// The path that needs to be checked needs to include the '/'
// This due to if the user has specified in skip_dir an exclusive path: '/path' - that is what must be matched
if (isDir(dirname)) {
if (selectiveSync.isDirNameExcluded(dirname.strip('.'))) {
// dont add a watch for this item
log.vdebug("Skipping monitoring due to skip_dir match: ", dirname);
return;
}
}
// is the filename a match to a skip_file entry?
if (selectiveSync.isFileNameExcluded(baseName(dirname))) {
// dont add a watch for this item
log.vdebug("Skipping monitoring due to skip_file match: ", dirname);
return;
if (isFile(dirname)) {
// Is the filename a match to a skip_file entry?
// The path that needs to be checked needs to include the '/'
// This due to if the user has specified in skip_file an exclusive path: '/path/file' - that is what must be matched
if (selectiveSync.isFileNameExcluded(dirname.strip('.'))) {
// dont add a watch for this item
log.vdebug("Skipping monitoring due to skip_file match: ", dirname);
return;
}
}
// is the path exluded by sync_list?
if (selectiveSync.isPathExcludedViaSyncList(buildNormalizedPath(dirname))) {
@ -231,6 +239,7 @@ final class Monitor
while (i < length) {
inotify_event *event = cast(inotify_event*) &buffer[i];
string path;
string evalPath;
// inotify event debug
log.vdebug("inotify event wd: ", event.wd);
log.vdebug("inotify event mask: ", event.mask);
@ -272,19 +281,38 @@ final class Monitor
// if the event is not to be ignored, obtain path
path = getPath(event);
// configure the skip_dir & skip skip_file comparison item
evalPath = path.strip('.');
// skip events that should be excluded based on application configuration
if (selectiveSync.isDirNameExcluded(path.strip('.').strip('/'))) {
goto skip;
}
if (selectiveSync.isFileNameExcluded(path.strip('.').strip('/'))) {
goto skip;
// Skip events that should be excluded based on application configuration
// We cant use isDir or isFile as this information is missing from the inotify event itself
// Thus this causes a segfault when attempting to query this - https://github.com/abraunegg/onedrive/issues/995
// Based on the 'type' of event & object type (directory or file) check that path against the 'right' user exclusions
// Directory events should only be compared against skip_dir and file events should only be compared against skip_file
if (event.mask & IN_ISDIR) {
// The event in question contains IN_ISDIR event mask, thus highly likely this is an event on a directory
// This due to if the user has specified in skip_dir an exclusive path: '/path' - that is what must be matched
if (selectiveSync.isDirNameExcluded(evalPath)) {
// The path to evaluate matches a path that the user has configured to skip
goto skip;
}
} else {
// The event in question missing the IN_ISDIR event mask, thus highly likely this is an event on a file
// This due to if the user has specified in skip_file an exclusive path: '/path/file' - that is what must be matched
if (selectiveSync.isFileNameExcluded(evalPath)) {
// The path to evaluate matches a file that the user has configured to skip
goto skip;
}
}
// is the path, excluded via sync_list
if (selectiveSync.isPathExcludedViaSyncList(path)) {
// The path to evaluate matches a directory or file that the user has configured not to include in the sync
goto skip;
}
// handle events
// handle the inotify events
if (event.mask & IN_MOVED_FROM) {
log.vdebug("event IN_MOVED_FROM: ", path);
cookieToPath[event.cookie] = path;

View file

@ -491,6 +491,16 @@ final class OneDriveApi
return get(url);
}
// https://docs.microsoft.com/en-us/onedrive/developer/rest-api/api/drive_get
JSONValue getDriveQuota(const(char)[] driveId)
{
checkAccessTokenExpired();
const(char)[] url;
url = driveByIdUrl ~ driveId ~ "/";
url ~= "?select=quota";
return get(url);
}
// https://docs.microsoft.com/en-us/onedrive/developer/rest-api/api/driveitem_delta
JSONValue viewChangesByItemId(const(char)[] driveId, const(char)[] id, const(char)[] deltaLink)
{
@ -628,7 +638,7 @@ final class OneDriveApi
return get(url);
}
// Return the requested details of the specified file id
// Return the requested details of the specified item id
// https://docs.microsoft.com/en-us/onedrive/developer/rest-api/api/driveitem_get
JSONValue getFileDetails(const(char)[] driveId, const(char)[] id)
{
@ -639,6 +649,17 @@ final class OneDriveApi
return get(url);
}
// Create an anonymous read-only shareable link for an existing file on OneDrive
// https://docs.microsoft.com/en-us/onedrive/developer/rest-api/api/driveitem_createlink
JSONValue createShareableLink(const(char)[] driveId, const(char)[] id, JSONValue accessScope)
{
checkAccessTokenExpired();
const(char)[] url;
url = driveByIdUrl ~ driveId ~ "/items/" ~ id ~ "/createLink";
http.addRequestHeader("Content-Type", "application/json");
return post(url, accessScope.toString());
}
// https://dev.onedrive.com/items/move.htm
JSONValue moveByPath(const(char)[] sourcePath, JSONValue moveData)
{
@ -703,10 +724,10 @@ final class OneDriveApi
}
// https://docs.microsoft.com/en-us/onedrive/developer/rest-api/api/site_search?view=odsp-graph-online
JSONValue o365SiteSearch(string o365SharedLibraryName){
JSONValue o365SiteSearch(){
checkAccessTokenExpired();
const(char)[] url;
url = siteSearchUrl ~ "=" ~ o365SharedLibraryName;
url = siteSearchUrl ~ "=*";
return get(url);
}
@ -1063,8 +1084,8 @@ final class OneDriveApi
}
} catch (CurlException e) {
// Parse and display error message received from OneDrive
log.vdebug("onedrive.perform() Generated a OneDrive CurlException");
log.error("ERROR: OneDrive returned an error with the following message:");
auto errorArray = splitLines(e.msg);
string errorMessage = errorArray[0];

View file

@ -4,7 +4,9 @@ import std.file;
import std.path;
import std.regex;
import std.stdio;
import std.string;
import util;
import log;
final class SelectiveSync
{
@ -83,6 +85,7 @@ final class SelectiveSync
// Does the directory name match skip_dir config entry?
// Returns true if the name matches a skip_dir config entry
// Returns false if no match
log.vdebug("skip_dir evaluation for: ", name);
// Try full path match first
if (!name.matchFirst(dirmask).empty) {
@ -91,8 +94,8 @@ final class SelectiveSync
// Do we check the base name as well?
if (!skipDirStrictMatch) {
// check just the basename in the path
string filename = baseName(name);
if(!filename.matchFirst(dirmask).empty) {
string parent = baseName(name);
if(!parent.matchFirst(dirmask).empty) {
return true;
}
}
@ -107,6 +110,7 @@ final class SelectiveSync
// Does the file name match skip_file config entry?
// Returns true if the name matches a skip_file config entry
// Returns false if no match
log.vdebug("skip_file evaluation for: ", name);
// Try full path match first
if (!name.matchFirst(mask).empty) {
@ -125,6 +129,7 @@ final class SelectiveSync
// Match against sync_list only
bool isPathExcludedViaSyncList(string path)
{
// Debug output that we are performing a 'sync_list' inclusion / exclusion test
return .isPathExcluded(path, paths);
}
@ -191,24 +196,104 @@ final class SelectiveSync
// if there are no allowed paths always return false
private bool isPathExcluded(string path, string[] allowedPaths)
{
// function variables
bool exclude = false;
bool finalResult = true; // will get updated to false, if pattern matched to sync_list entry
int offset;
string wildcard = "*";
// always allow the root
if (path == ".") return false;
// if there are no allowed paths always return false
if (allowedPaths.empty) return false;
path = buildNormalizedPath(path);
foreach (allowed; allowedPaths) {
auto comm = commonPrefix(path, allowed);
log.vdebug("Evaluation against 'sync_list' for: ", path);
// unless path is an exact match, entire sync_list entries need to be processed to ensure
// negative matches are also correctly detected
foreach (allowedPath; allowedPaths) {
// is this an inclusion path or finer grained exclusion?
switch (allowedPath[0]) {
case '-':
// allowed path starts with '-', this user wants to exclude this path
exclude = true;
offset = 1;
break;
case '!':
// allowed path starts with '!', this user wants to exclude this path
exclude = true;
offset = 1;
break;
case '/':
// allowed path starts with '/', this user wants to include this path
// but a '/' at the start causes matching issues, so use the offset for comparison
exclude = false;
offset = 1;
break;
default:
// no negative pattern, default is to not exclude
exclude = false;
offset = 0;
}
// What are we comparing against?
log.vdebug("Evaluation against 'sync_list' entry: ", allowedPath);
// Generate the common prefix from the path vs the allowed path
auto comm = commonPrefix(path, allowedPath[offset..$]);
// is path is an exact match of the allowed path
if (comm.length == path.length) {
// the given path is contained in an allowed path
return false;
if (!exclude) {
log.vdebug("Evaluation against 'sync_list' result: direct match");
finalResult = false;
// direct match, break and go sync
break;
} else {
log.vdebug("Evaluation against 'sync_list' result: direct match but to be excluded");
finalResult = true;
}
}
if (comm.length == allowed.length && path[comm.length] == '/') {
// is path is a subitem of the allowed path
if (comm.length == allowedPath[offset..$].length) {
// the given path is a subitem of an allowed path
return false;
if (!exclude) {
log.vdebug("Evaluation against 'sync_list' result: parental path match");
finalResult = false;
} else {
log.vdebug("Evaluation against 'sync_list' result: parental path match but to be excluded");
finalResult = true;
}
}
// does the allowed path contain a wildcard? (*)
if (canFind(allowedPath[offset..$], wildcard)) {
// allowed path contains a wildcard
// manually replace '*' for '.*' to be compatible with regex
string regexCompatiblePath = replace(allowedPath[offset..$], "*", ".*");
auto allowedMask = regex(regexCompatiblePath);
if (matchAll(path, allowedMask)) {
// regex wildcard evaluation matches
if (!exclude) {
log.vdebug("Evaluation against 'sync_list' result: wildcard pattern match");
finalResult = false;
} else {
log.vdebug("Evaluation against 'sync_list' result: wildcard pattern match but to be excluded");
finalResult = true;
}
}
}
}
return true;
// results
if (finalResult) {
log.vdebug("Evaluation against 'sync_list' final result: EXCLUDED");
} else {
log.vdebug("Evaluation against 'sync_list' final result: included for sync");
}
return finalResult;
}
// test if the given path is matched by the regex expression.

File diff suppressed because it is too large Load diff

View file

@ -195,7 +195,6 @@ bool isValidName(string path)
matched = m.empty;
// Additional explicit validation checks
if (itemName == "Icon") {matched = false;}
if (itemName == ".lock") {matched = false;}
if (itemName == "desktop.ini") {matched = false;}
// _vti_ cannot appear anywhere in a file or folder name