mirror of
https://github.com/trapexit/mergerfs.git
synced 2024-11-22 11:39:52 +08:00
add tagging branches RW/RO/NW
This allows users to tag a branch as readonly or not for writing regardless of how the filesystem is mounted. Should simplify deployments and offer more flexibility.
This commit is contained in:
parent
8dd0dc11ee
commit
b55ebba4ed
64
README.md
64
README.md
|
@ -8,7 +8,7 @@ mergerfs - a featureful union filesystem
|
|||
|
||||
# SYNOPSIS
|
||||
|
||||
mergerfs -o<options> <srcmounts> <mountpoint>
|
||||
mergerfs -o<options> <branches> <mountpoint>
|
||||
|
||||
# DESCRIPTION
|
||||
|
||||
|
@ -81,11 +81,13 @@ mergerfs does **not** support the copy-on-write (CoW) behavior found in **aufs**
|
|||
|
||||
**NOTE:** Options are evaluated in the order listed so if the options are **func.rmdir=rand,category.action=ff** the **action** category setting will override the **rmdir** setting.
|
||||
|
||||
### srcmounts
|
||||
### branches
|
||||
|
||||
The srcmounts (source mounts) argument is a colon (':') delimited list of paths to be included in the pool. It does not matter if the paths are on the same or different drives nor does it matter the filesystem. Used and available space will not be duplicated for paths on the same device and any features which aren't supported by the underlying filesystem (such as file attributes or extended attributes) will return the appropriate errors.
|
||||
The 'branches' (formerly 'srcmounts') argument is a colon (':') delimited list of paths to be pooled together. It does not matter if the paths are on the same or different drives nor does it matter the filesystem. Used and available space will not be duplicated for paths on the same device and any features which aren't supported by the underlying filesystem (such as file attributes or extended attributes) will return the appropriate errors.
|
||||
|
||||
To make it easier to include multiple source mounts mergerfs supports [globbing](http://linux.die.net/man/7/glob). **The globbing tokens MUST be escaped when using via the shell else the shell itself will expand it.**
|
||||
To make it easier to include multiple branches mergerfs supports [globbing](http://linux.die.net/man/7/glob). **The globbing tokens MUST be escaped when using via the shell else the shell itself will apply the glob itself.**
|
||||
|
||||
Each branch can have a suffix of `=RW` (read / write), `=RO` (read only), or `=NW` (no writes). These suffixes work with globs as well and will apply to each path found. `RW` is the default behavior and those paths will be eligible for all policy categories. `RO` will exclude those paths from `create` and `action` policies (just as a filesystem being mounted `ro` would). `NW` will exclude those paths from `create` policies (you can't create but you can change / delete).
|
||||
|
||||
```
|
||||
$ mergerfs -o defaults,allow_other,use_ino /mnt/disk\*:/mnt/cdrom /media/drives
|
||||
|
@ -176,34 +178,38 @@ Policies, as described below, are of two core types. `path preserving` and `non-
|
|||
|
||||
All policies which start with `ep` (**epff**, **eplfs**, **eplus**, **epmfs**, **eprand**) are `path preserving`. `ep` stands for `existing path`.
|
||||
|
||||
As the descriptions explain a path preserving policy will only consider drives where the relative path being accessed already exists.
|
||||
A path preserving policy will only consider drives where the relative path being accessed already exists.
|
||||
|
||||
When using non-path preserving policies paths will be cloned to target drives as necessary.
|
||||
|
||||
#### Policy descriptions
|
||||
|
||||
All **create** policies will filter out branches which are mounted **read only** or tagged as **read only** or **no write**. All **action** policies will filter out branches which are mounted or tagged as **read only**.
|
||||
|
||||
If all branches are filtered an error will be returned. Typically EROFS or ENOSPC.
|
||||
|
||||
| Policy | Description |
|
||||
|------------------|------------------------------------------------------------|
|
||||
| all | Search category: acts like **ff**. Action category: apply to all found. Create category: for **mkdir**, **mknod**, and **symlink** it will apply to all found. **create** works like **ff**. It will exclude readonly drives and those with free space less than **minfreespace**. |
|
||||
| epall (existing path, all) | Search category: acts like **epff**. Action category: apply to all found. Create category: for **mkdir**, **mknod**, and **symlink** it will apply to all existing paths found. **create** works like **epff**. Excludes readonly drives and those with free space less than **minfreespace**. |
|
||||
| epff (existing path, first found) | Given the order of the drives, as defined at mount time or configured at runtime, act on the first one found where the relative path already exists. For **create** category functions it will exclude readonly drives and those with free space less than **minfreespace** (unless there is no other option). Falls back to **ff**. |
|
||||
| eplfs (existing path, least free space) | Of all the drives on which the relative path exists choose the drive with the least free space. For **create** category functions it will exclude readonly drives and those with free space less than **minfreespace**. Falls back to **lfs**. |
|
||||
| eplus (existing path, least used space) | Of all the drives on which the relative path exists choose the drive with the least used space. For **create** category functions it will exclude readonly drives and those with free space less than **minfreespace**. Falls back to **lus**. |
|
||||
| epmfs (existing path, most free space) | Of all the drives on which the relative path exists choose the drive with the most free space. For **create** category functions it will exclude readonly drives and those with free space less than **minfreespace**. Falls back to **mfs**. |
|
||||
| all | Search category: acts like **ff**. Action category: apply to all found. Create category: for **mkdir**, **mknod**, and **symlink** it will apply to all branches. **create** works like **ff**. It will exclude branches with free space less than **minfreespace**. |
|
||||
| epall (existing path, all) | Search category: acts like **epff**. Action category: apply to all found. Create category: for **mkdir**, **mknod**, and **symlink** it will apply to all existing paths found. **create** works like **epff**. Excludes branches with free space less than **minfreespace**. |
|
||||
| epff (existing path, first found) | Given the order of the drives, as defined at mount time or configured at runtime, act on the first one found where the relative path already exists. For **create** category functions it will exclude branches with free space less than **minfreespace**. |
|
||||
| eplfs (existing path, least free space) | Of all the drives on which the relative path exists choose the drive with the least free space. For **create** category functions it will exclude those with free space less than **minfreespace**. |
|
||||
| eplus (existing path, least used space) | Of all the drives on which the relative path exists choose the drive with the least used space. For **create** category functions it will exclude those with free space less than **minfreespace**. |
|
||||
| epmfs (existing path, most free space) | Of all the drives on which the relative path exists choose the drive with the most free space. For **create** category functions it will exclude those with free space less than **minfreespace**. |
|
||||
| eprand (existing path, random) | Calls **epall** and then randomizes. Otherwise behaves the same as **epall**. |
|
||||
| erofs | Exclusively return **-1** with **errno** set to **EROFS** (Read-only filesystem). By setting **create** functions to this you can in effect turn the filesystem mostly readonly. |
|
||||
| ff (first found) | Given the order of the drives, as defined at mount time or configured at runtime, act on the first one found. For **create** category functions it will exclude readonly drives and those with free space less than **minfreespace** (unless there is no other option). |
|
||||
| lfs (least free space) | Pick the drive with the least available free space. For **create** category functions it will exclude readonly drives and those with free space less than **minfreespace**. Falls back to **mfs**. |
|
||||
| lus (least used space) | Pick the drive with the least used space. For **create** category functions it will exclude readonly drives and those with free space less than **minfreespace**. Falls back to **mfs**. |
|
||||
| mfs (most free space) | Pick the drive with the most available free space. For **create** category functions it will exclude readonly drives. Falls back to **ff**. |
|
||||
| newest | Pick the file / directory with the largest mtime. For **create** category functions it will exclude readonly drives and those with free space less than **minfreespace** (unless there is no other option). |
|
||||
| erofs | Exclusively return **-1** with **errno** set to **EROFS** (Read-only filesystem). |
|
||||
| ff (first found) | Given the order of the drives, as defined at mount time or configured at runtime, act on the first one found. For **create** category functions it will exclude those with free space less than **minfreespace**. |
|
||||
| lfs (least free space) | Pick the drive with the least available free space. For **create** category functions it will exclude those with free space less than **minfreespace**. |
|
||||
| lus (least used space) | Pick the drive with the least used space. For **create** category functions it will exclude those with free space less than **minfreespace**. |
|
||||
| mfs (most free space) | Pick the drive with the most available free space. |
|
||||
| newest | Pick the file / directory with the largest mtime. For **create** category functions it will exclude those with free space less than **minfreespace**. |
|
||||
| rand (random) | Calls **all** and then randomizes. |
|
||||
|
||||
#### Defaults ####
|
||||
|
||||
| Category | Policy |
|
||||
|----------|--------|
|
||||
| action | all |
|
||||
| action | epall |
|
||||
| create | epmfs |
|
||||
| search | ff |
|
||||
|
||||
|
@ -253,7 +259,7 @@ The above behavior will help minimize the likelihood of EXDEV being returned but
|
|||
|
||||
#### statvfs ####
|
||||
|
||||
[statvfs](http://linux.die.net/man/2/statvfs) normalizes the source drives based on the fragment size and sums the number of adjusted blocks and inodes. This means you will see the combined space of all sources. Total, used, and free. The sources however are dedupped based on the drive so multiple sources on the same drive will not result in double counting it's space. Filesystems mounted further down the tree of the src mounts will not be included.
|
||||
[statvfs](http://linux.die.net/man/2/statvfs) normalizes the source drives based on the fragment size and sums the number of adjusted blocks and inodes. This means you will see the combined space of all sources. Total, used, and free. The sources however are dedupped based on the drive so multiple sources on the same drive will not result in double counting it's space. Filesystems mounted further down the tree of the branch will not be included.
|
||||
|
||||
# BUILDING
|
||||
|
||||
|
@ -328,7 +334,9 @@ Any changes made at runtime are **not** persisted. If you wish for values to per
|
|||
|
||||
Use `xattr -l /mount/point/.mergerfs` to see all supported keys. Some are informational and therefore readonly.
|
||||
|
||||
###### user.mergerfs.srcmounts ######
|
||||
###### user.mergerfs.branches ######
|
||||
|
||||
**NOTE:** formerly `user.mergerfs.srcmounts` but said key is still supported.
|
||||
|
||||
Used to query or modify the list of source mounts. When modifying there are several shortcuts to easy manipulation of the list.
|
||||
|
||||
|
@ -341,7 +349,7 @@ Used to query or modify the list of source mounts. When modifying there are seve
|
|||
| -< | remove first in list |
|
||||
| -> | remove last in list |
|
||||
|
||||
`xattr -w user.mergerfs.srcmounts +</mnt/drive3 /mnt/pool/.mergerfs`
|
||||
`xattr -w user.mergerfs.branches +</mnt/drive3 /mnt/pool/.mergerfs`
|
||||
|
||||
###### minfreespace ######
|
||||
|
||||
|
@ -365,7 +373,7 @@ Output: the policy string except for categories where its funcs have multiple ty
|
|||
|
||||
```
|
||||
[trapexit:/mnt/mergerfs] $ xattr -l .mergerfs
|
||||
user.mergerfs.srcmounts: /mnt/a:/mnt/b
|
||||
user.mergerfs.branches: /mnt/a:/mnt/b
|
||||
user.mergerfs.minfreespace: 4294967295
|
||||
user.mergerfs.moveonenospc: false
|
||||
...
|
||||
|
@ -377,16 +385,16 @@ ff
|
|||
[trapexit:/mnt/mergerfs] $ xattr -p user.mergerfs.category.search .mergerfs
|
||||
newest
|
||||
|
||||
[trapexit:/mnt/mergerfs] $ xattr -w user.mergerfs.srcmounts +/mnt/c .mergerfs
|
||||
[trapexit:/mnt/mergerfs] $ xattr -p user.mergerfs.srcmounts .mergerfs
|
||||
[trapexit:/mnt/mergerfs] $ xattr -w user.mergerfs.branches +/mnt/c .mergerfs
|
||||
[trapexit:/mnt/mergerfs] $ xattr -p user.mergerfs.branches .mergerfs
|
||||
/mnt/a:/mnt/b:/mnt/c
|
||||
|
||||
[trapexit:/mnt/mergerfs] $ xattr -w user.mergerfs.srcmounts =/mnt/c .mergerfs
|
||||
[trapexit:/mnt/mergerfs] $ xattr -p user.mergerfs.srcmounts .mergerfs
|
||||
[trapexit:/mnt/mergerfs] $ xattr -w user.mergerfs.branches =/mnt/c .mergerfs
|
||||
[trapexit:/mnt/mergerfs] $ xattr -p user.mergerfs.branches .mergerfs
|
||||
/mnt/c
|
||||
|
||||
[trapexit:/mnt/mergerfs] $ xattr -w user.mergerfs.srcmounts '+</mnt/a:/mnt/b' .mergerfs
|
||||
[trapexit:/mnt/mergerfs] $ xattr -p user.mergerfs.srcmounts .mergerfs
|
||||
[trapexit:/mnt/mergerfs] $ xattr -w user.mergerfs.branches '+</mnt/a:/mnt/b' .mergerfs
|
||||
[trapexit:/mnt/mergerfs] $ xattr -p user.mergerfs.branches .mergerfs
|
||||
/mnt/a:/mnt/b:/mnt/c
|
||||
```
|
||||
|
||||
|
|
113
man/mergerfs.1
113
man/mergerfs.1
|
@ -8,7 +8,7 @@
|
|||
mergerfs \- a featureful union filesystem
|
||||
.SH SYNOPSIS
|
||||
.PP
|
||||
mergerfs \-o<options> <srcmounts> <mountpoint>
|
||||
mergerfs \-o<options> <branches> <mountpoint>
|
||||
.SH DESCRIPTION
|
||||
.PP
|
||||
\f[B]mergerfs\f[] is a union filesystem geared towards simplifying
|
||||
|
@ -202,10 +202,10 @@ Example: \f[B]category.create=mfs\f[]
|
|||
options are \f[B]func.rmdir=rand,category.action=ff\f[] the
|
||||
\f[B]action\f[] category setting will override the \f[B]rmdir\f[]
|
||||
setting.
|
||||
.SS srcmounts
|
||||
.SS branches
|
||||
.PP
|
||||
The srcmounts (source mounts) argument is a colon (\[aq]:\[aq])
|
||||
delimited list of paths to be included in the pool.
|
||||
The \[aq]branches\[aq] (formerly \[aq]srcmounts\[aq]) argument is a
|
||||
colon (\[aq]:\[aq]) delimited list of paths to be pooled together.
|
||||
It does not matter if the paths are on the same or different drives nor
|
||||
does it matter the filesystem.
|
||||
Used and available space will not be duplicated for paths on the same
|
||||
|
@ -213,10 +213,22 @@ device and any features which aren\[aq]t supported by the underlying
|
|||
filesystem (such as file attributes or extended attributes) will return
|
||||
the appropriate errors.
|
||||
.PP
|
||||
To make it easier to include multiple source mounts mergerfs supports
|
||||
To make it easier to include multiple branches mergerfs supports
|
||||
globbing (http://linux.die.net/man/7/glob).
|
||||
\f[B]The globbing tokens MUST be escaped when using via the shell else
|
||||
the shell itself will expand it.\f[]
|
||||
the shell itself will apply the glob itself.\f[]
|
||||
.PP
|
||||
Each branch can have a suffix of \f[C]=RW\f[] (read / write),
|
||||
\f[C]=RO\f[] (read only), or \f[C]=NW\f[] (no writes).
|
||||
These suffixes work with globs as well and will apply to each path
|
||||
found.
|
||||
\f[C]RW\f[] is the default behavior and those paths will be eligible for
|
||||
all policy categories.
|
||||
\f[C]RO\f[] will exclude those paths from \f[C]create\f[] and
|
||||
\f[C]action\f[] policies (just as a filesystem being mounted \f[C]ro\f[]
|
||||
would).
|
||||
\f[C]NW\f[] will exclude those paths from \f[C]create\f[] policies (you
|
||||
can\[aq]t create but you can change / delete).
|
||||
.IP
|
||||
.nf
|
||||
\f[C]
|
||||
|
@ -413,13 +425,21 @@ All policies which start with \f[C]ep\f[] (\f[B]epff\f[],
|
|||
\f[C]path\ preserving\f[].
|
||||
\f[C]ep\f[] stands for \f[C]existing\ path\f[].
|
||||
.PP
|
||||
As the descriptions explain a path preserving policy will only consider
|
||||
drives where the relative path being accessed already exists.
|
||||
A path preserving policy will only consider drives where the relative
|
||||
path being accessed already exists.
|
||||
.PP
|
||||
When using non\-path preserving policies paths will be cloned to target
|
||||
drives as necessary.
|
||||
.SS Policy descriptions
|
||||
.PP
|
||||
All \f[B]create\f[] policies will filter out branches which are mounted
|
||||
\f[B]read only\f[] or tagged as \f[B]read only\f[] or \f[B]no write\f[].
|
||||
All \f[B]action\f[] policies will filter out branches which are mounted
|
||||
or tagged as \f[B]read only\f[].
|
||||
.PP
|
||||
If all branches are filtered an error will be returned.
|
||||
Typically EROFS or ENOSPC.
|
||||
.PP
|
||||
.TS
|
||||
tab(@);
|
||||
lw(16.6n) lw(53.4n).
|
||||
|
@ -435,9 +455,9 @@ T}@T{
|
|||
Search category: acts like \f[B]ff\f[].
|
||||
Action category: apply to all found.
|
||||
Create category: for \f[B]mkdir\f[], \f[B]mknod\f[], and
|
||||
\f[B]symlink\f[] it will apply to all found.
|
||||
\f[B]symlink\f[] it will apply to all branches.
|
||||
\f[B]create\f[] works like \f[B]ff\f[].
|
||||
It will exclude readonly drives and those with free space less than
|
||||
It will exclude branches with free space less than
|
||||
\f[B]minfreespace\f[].
|
||||
T}
|
||||
T{
|
||||
|
@ -448,8 +468,7 @@ Action category: apply to all found.
|
|||
Create category: for \f[B]mkdir\f[], \f[B]mknod\f[], and
|
||||
\f[B]symlink\f[] it will apply to all existing paths found.
|
||||
\f[B]create\f[] works like \f[B]epff\f[].
|
||||
Excludes readonly drives and those with free space less than
|
||||
\f[B]minfreespace\f[].
|
||||
Excludes branches with free space less than \f[B]minfreespace\f[].
|
||||
T}
|
||||
T{
|
||||
epff (existing path, first found)
|
||||
|
@ -457,37 +476,32 @@ T}@T{
|
|||
Given the order of the drives, as defined at mount time or configured at
|
||||
runtime, act on the first one found where the relative path already
|
||||
exists.
|
||||
For \f[B]create\f[] category functions it will exclude readonly drives
|
||||
and those with free space less than \f[B]minfreespace\f[] (unless there
|
||||
is no other option).
|
||||
Falls back to \f[B]ff\f[].
|
||||
For \f[B]create\f[] category functions it will exclude branches with
|
||||
free space less than \f[B]minfreespace\f[].
|
||||
T}
|
||||
T{
|
||||
eplfs (existing path, least free space)
|
||||
T}@T{
|
||||
Of all the drives on which the relative path exists choose the drive
|
||||
with the least free space.
|
||||
For \f[B]create\f[] category functions it will exclude readonly drives
|
||||
and those with free space less than \f[B]minfreespace\f[].
|
||||
Falls back to \f[B]lfs\f[].
|
||||
For \f[B]create\f[] category functions it will exclude those with free
|
||||
space less than \f[B]minfreespace\f[].
|
||||
T}
|
||||
T{
|
||||
eplus (existing path, least used space)
|
||||
T}@T{
|
||||
Of all the drives on which the relative path exists choose the drive
|
||||
with the least used space.
|
||||
For \f[B]create\f[] category functions it will exclude readonly drives
|
||||
and those with free space less than \f[B]minfreespace\f[].
|
||||
Falls back to \f[B]lus\f[].
|
||||
For \f[B]create\f[] category functions it will exclude those with free
|
||||
space less than \f[B]minfreespace\f[].
|
||||
T}
|
||||
T{
|
||||
epmfs (existing path, most free space)
|
||||
T}@T{
|
||||
Of all the drives on which the relative path exists choose the drive
|
||||
with the most free space.
|
||||
For \f[B]create\f[] category functions it will exclude readonly drives
|
||||
and those with free space less than \f[B]minfreespace\f[].
|
||||
Falls back to \f[B]mfs\f[].
|
||||
For \f[B]create\f[] category functions it will exclude those with free
|
||||
space less than \f[B]minfreespace\f[].
|
||||
T}
|
||||
T{
|
||||
eprand (existing path, random)
|
||||
|
@ -500,48 +514,40 @@ erofs
|
|||
T}@T{
|
||||
Exclusively return \f[B]\-1\f[] with \f[B]errno\f[] set to
|
||||
\f[B]EROFS\f[] (Read\-only filesystem).
|
||||
By setting \f[B]create\f[] functions to this you can in effect turn the
|
||||
filesystem mostly readonly.
|
||||
T}
|
||||
T{
|
||||
ff (first found)
|
||||
T}@T{
|
||||
Given the order of the drives, as defined at mount time or configured at
|
||||
runtime, act on the first one found.
|
||||
For \f[B]create\f[] category functions it will exclude readonly drives
|
||||
and those with free space less than \f[B]minfreespace\f[] (unless there
|
||||
is no other option).
|
||||
For \f[B]create\f[] category functions it will exclude those with free
|
||||
space less than \f[B]minfreespace\f[].
|
||||
T}
|
||||
T{
|
||||
lfs (least free space)
|
||||
T}@T{
|
||||
Pick the drive with the least available free space.
|
||||
For \f[B]create\f[] category functions it will exclude readonly drives
|
||||
and those with free space less than \f[B]minfreespace\f[].
|
||||
Falls back to \f[B]mfs\f[].
|
||||
For \f[B]create\f[] category functions it will exclude those with free
|
||||
space less than \f[B]minfreespace\f[].
|
||||
T}
|
||||
T{
|
||||
lus (least used space)
|
||||
T}@T{
|
||||
Pick the drive with the least used space.
|
||||
For \f[B]create\f[] category functions it will exclude readonly drives
|
||||
and those with free space less than \f[B]minfreespace\f[].
|
||||
Falls back to \f[B]mfs\f[].
|
||||
For \f[B]create\f[] category functions it will exclude those with free
|
||||
space less than \f[B]minfreespace\f[].
|
||||
T}
|
||||
T{
|
||||
mfs (most free space)
|
||||
T}@T{
|
||||
Pick the drive with the most available free space.
|
||||
For \f[B]create\f[] category functions it will exclude readonly drives.
|
||||
Falls back to \f[B]ff\f[].
|
||||
T}
|
||||
T{
|
||||
newest
|
||||
T}@T{
|
||||
Pick the file / directory with the largest mtime.
|
||||
For \f[B]create\f[] category functions it will exclude readonly drives
|
||||
and those with free space less than \f[B]minfreespace\f[] (unless there
|
||||
is no other option).
|
||||
For \f[B]create\f[] category functions it will exclude those with free
|
||||
space less than \f[B]minfreespace\f[].
|
||||
T}
|
||||
T{
|
||||
rand (random)
|
||||
|
@ -563,7 +569,7 @@ _
|
|||
T{
|
||||
action
|
||||
T}@T{
|
||||
all
|
||||
epall
|
||||
T}
|
||||
T{
|
||||
create
|
||||
|
@ -694,7 +700,7 @@ This means you will see the combined space of all sources.
|
|||
Total, used, and free.
|
||||
The sources however are dedupped based on the drive so multiple sources
|
||||
on the same drive will not result in double counting it\[aq]s space.
|
||||
Filesystems mounted further down the tree of the src mounts will not be
|
||||
Filesystems mounted further down the tree of the branch will not be
|
||||
included.
|
||||
.SH BUILDING
|
||||
.PP
|
||||
|
@ -787,7 +793,10 @@ wherever you configure the mounting of mergerfs (/etc/fstab).
|
|||
Use \f[C]xattr\ \-l\ /mount/point/.mergerfs\f[] to see all supported
|
||||
keys.
|
||||
Some are informational and therefore readonly.
|
||||
.SS user.mergerfs.srcmounts
|
||||
.SS user.mergerfs.branches
|
||||
.PP
|
||||
\f[B]NOTE:\f[] formerly \f[C]user.mergerfs.srcmounts\f[] but said key is
|
||||
still supported.
|
||||
.PP
|
||||
Used to query or modify the list of source mounts.
|
||||
When modifying there are several shortcuts to easy manipulation of the
|
||||
|
@ -834,7 +843,7 @@ remove last in list
|
|||
T}
|
||||
.TE
|
||||
.PP
|
||||
\f[C]xattr\ \-w\ user.mergerfs.srcmounts\ +</mnt/drive3\ /mnt/pool/.mergerfs\f[]
|
||||
\f[C]xattr\ \-w\ user.mergerfs.branches\ +</mnt/drive3\ /mnt/pool/.mergerfs\f[]
|
||||
.SS minfreespace
|
||||
.PP
|
||||
Input: interger with an optional multiplier suffix.
|
||||
|
@ -858,7 +867,7 @@ In that case it will be a comma separated list
|
|||
.nf
|
||||
\f[C]
|
||||
[trapexit:/mnt/mergerfs]\ $\ xattr\ \-l\ .mergerfs
|
||||
user.mergerfs.srcmounts:\ /mnt/a:/mnt/b
|
||||
user.mergerfs.branches:\ /mnt/a:/mnt/b
|
||||
user.mergerfs.minfreespace:\ 4294967295
|
||||
user.mergerfs.moveonenospc:\ false
|
||||
\&...
|
||||
|
@ -870,16 +879,16 @@ ff
|
|||
[trapexit:/mnt/mergerfs]\ $\ xattr\ \-p\ user.mergerfs.category.search\ .mergerfs
|
||||
newest
|
||||
|
||||
[trapexit:/mnt/mergerfs]\ $\ xattr\ \-w\ user.mergerfs.srcmounts\ +/mnt/c\ .mergerfs
|
||||
[trapexit:/mnt/mergerfs]\ $\ xattr\ \-p\ user.mergerfs.srcmounts\ .mergerfs
|
||||
[trapexit:/mnt/mergerfs]\ $\ xattr\ \-w\ user.mergerfs.branches\ +/mnt/c\ .mergerfs
|
||||
[trapexit:/mnt/mergerfs]\ $\ xattr\ \-p\ user.mergerfs.branches\ .mergerfs
|
||||
/mnt/a:/mnt/b:/mnt/c
|
||||
|
||||
[trapexit:/mnt/mergerfs]\ $\ xattr\ \-w\ user.mergerfs.srcmounts\ =/mnt/c\ .mergerfs
|
||||
[trapexit:/mnt/mergerfs]\ $\ xattr\ \-p\ user.mergerfs.srcmounts\ .mergerfs
|
||||
[trapexit:/mnt/mergerfs]\ $\ xattr\ \-w\ user.mergerfs.branches\ =/mnt/c\ .mergerfs
|
||||
[trapexit:/mnt/mergerfs]\ $\ xattr\ \-p\ user.mergerfs.branches\ .mergerfs
|
||||
/mnt/c
|
||||
|
||||
[trapexit:/mnt/mergerfs]\ $\ xattr\ \-w\ user.mergerfs.srcmounts\ \[aq]+</mnt/a:/mnt/b\[aq]\ .mergerfs
|
||||
[trapexit:/mnt/mergerfs]\ $\ xattr\ \-p\ user.mergerfs.srcmounts\ .mergerfs
|
||||
[trapexit:/mnt/mergerfs]\ $\ xattr\ \-w\ user.mergerfs.branches\ \[aq]+</mnt/a:/mnt/b\[aq]\ .mergerfs
|
||||
[trapexit:/mnt/mergerfs]\ $\ xattr\ \-p\ user.mergerfs.branches\ .mergerfs
|
||||
/mnt/a:/mnt/b:/mnt/c
|
||||
\f[]
|
||||
.fi
|
||||
|
|
|
@ -32,7 +32,7 @@ using mergerfs::Category;
|
|||
static
|
||||
int
|
||||
_access(Policy::Func::Search searchFunc,
|
||||
const vector<string> &srcmounts,
|
||||
const Branches &branches_,
|
||||
const uint64_t minfreespace,
|
||||
const char *fusepath,
|
||||
const int mask)
|
||||
|
@ -41,7 +41,7 @@ _access(Policy::Func::Search searchFunc,
|
|||
string fullpath;
|
||||
vector<const string*> basepaths;
|
||||
|
||||
rv = searchFunc(srcmounts,fusepath,minfreespace,basepaths);
|
||||
rv = searchFunc(branches_,fusepath,minfreespace,basepaths);
|
||||
if(rv == -1)
|
||||
return -errno;
|
||||
|
||||
|
@ -63,10 +63,10 @@ namespace mergerfs
|
|||
const fuse_context *fc = fuse_get_context();
|
||||
const Config &config = Config::get(fc);
|
||||
const ugid::Set ugid(fc->uid,fc->gid);
|
||||
const rwlock::ReadGuard readlock(&config.srcmountslock);
|
||||
const rwlock::ReadGuard readlock(&config.branches_lock);
|
||||
|
||||
return _access(config.access,
|
||||
config.srcmounts,
|
||||
config.branches,
|
||||
config.minfreespace,
|
||||
fusepath,
|
||||
mask);
|
||||
|
|
216
src/branch.cpp
Normal file
216
src/branch.cpp
Normal file
|
@ -0,0 +1,216 @@
|
|||
/*
|
||||
ISC License
|
||||
|
||||
Copyright (c) 2018, Antonio SJ Musumeci <trapexit@spawn.link>
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "branch.hpp"
|
||||
#include "fs.hpp"
|
||||
#include "fs_glob.hpp"
|
||||
#include "str.hpp"
|
||||
|
||||
#include <fnmatch.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
using std::string;
|
||||
using std::vector;
|
||||
|
||||
bool
|
||||
Branch::ro(void) const
|
||||
{
|
||||
return (mode == Branch::RO);
|
||||
}
|
||||
|
||||
bool
|
||||
Branch::ro_or_nw(void) const
|
||||
{
|
||||
return ((mode == Branch::RO) ||
|
||||
(mode == Branch::NW));
|
||||
}
|
||||
|
||||
string
|
||||
Branches::to_string(const bool mode_) const
|
||||
{
|
||||
string tmp;
|
||||
|
||||
for(size_t i = 0; i < size(); i++)
|
||||
{
|
||||
const Branch &branch = (*this)[i];
|
||||
|
||||
tmp += branch.path;
|
||||
|
||||
if(mode_)
|
||||
{
|
||||
tmp += '=';
|
||||
switch(branch.mode)
|
||||
{
|
||||
default:
|
||||
case Branch::RW:
|
||||
tmp += "RW";
|
||||
break;
|
||||
case Branch::RO:
|
||||
tmp += "RO";
|
||||
break;
|
||||
case Branch::NW:
|
||||
tmp += "NW";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
tmp += ':';
|
||||
}
|
||||
|
||||
if(*tmp.rbegin() == ':')
|
||||
tmp.erase(tmp.size() - 1);
|
||||
|
||||
return tmp;
|
||||
}
|
||||
|
||||
void
|
||||
Branches::to_paths(vector<string> &vec_) const
|
||||
{
|
||||
for(size_t i = 0; i < size(); i++)
|
||||
{
|
||||
const Branch &branch = (*this)[i];
|
||||
|
||||
vec_.push_back(branch.path);
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
parse(const string &str_,
|
||||
Branches &branches_)
|
||||
{
|
||||
string str;
|
||||
Branch branch;
|
||||
vector<string> globbed;
|
||||
|
||||
str = str_;
|
||||
branch.mode = Branch::INVALID;
|
||||
if(str::ends_with(str,"=RO"))
|
||||
branch.mode = Branch::RO;
|
||||
else if(str::ends_with(str,"=RW"))
|
||||
branch.mode = Branch::RW;
|
||||
else if(str::ends_with(str,"=NW"))
|
||||
branch.mode = Branch::NW;
|
||||
|
||||
if(branch.mode != Branch::INVALID)
|
||||
str.resize(str.size() - 3);
|
||||
else
|
||||
branch.mode = Branch::RW;
|
||||
|
||||
fs::glob(str,globbed);
|
||||
fs::realpathize(globbed);
|
||||
for(size_t i = 0; i < globbed.size(); i++)
|
||||
{
|
||||
branch.path = globbed[i];
|
||||
branches_.push_back(branch);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Branches::set(const std::string &str_)
|
||||
{
|
||||
vector<string> paths;
|
||||
|
||||
clear();
|
||||
|
||||
str::split(paths,str_,':');
|
||||
|
||||
for(size_t i = 0; i < paths.size(); i++)
|
||||
{
|
||||
Branches branches;
|
||||
|
||||
parse(paths[i],branches);
|
||||
|
||||
insert(end(),
|
||||
branches.begin(),
|
||||
branches.end());
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Branches::add_begin(const std::string &str_)
|
||||
{
|
||||
vector<string> paths;
|
||||
|
||||
str::split(paths,str_,':');
|
||||
|
||||
for(size_t i = 0; i < paths.size(); i++)
|
||||
{
|
||||
Branches branches;
|
||||
|
||||
parse(paths[i],branches);
|
||||
|
||||
insert(begin(),
|
||||
branches.begin(),
|
||||
branches.end());
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Branches::add_end(const std::string &str_)
|
||||
{
|
||||
vector<string> paths;
|
||||
|
||||
str::split(paths,str_,':');
|
||||
|
||||
for(size_t i = 0; i < paths.size(); i++)
|
||||
{
|
||||
Branches branches;
|
||||
|
||||
parse(paths[i],branches);
|
||||
|
||||
insert(end(),
|
||||
branches.begin(),
|
||||
branches.end());
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Branches::erase_begin(void)
|
||||
{
|
||||
erase(begin());
|
||||
}
|
||||
|
||||
void
|
||||
Branches::erase_end(void)
|
||||
{
|
||||
pop_back();
|
||||
}
|
||||
|
||||
void
|
||||
Branches::erase_fnmatch(const std::string &str_)
|
||||
{
|
||||
vector<string> patterns;
|
||||
|
||||
str::split(patterns,str_,':');
|
||||
|
||||
for(iterator i = begin(); i != end();)
|
||||
{
|
||||
int match = FNM_NOMATCH;
|
||||
|
||||
for(vector<string>::const_iterator pi = patterns.begin();
|
||||
pi != patterns.end() && match != 0;
|
||||
++pi)
|
||||
{
|
||||
match = ::fnmatch(pi->c_str(),i->path.c_str(),0);
|
||||
}
|
||||
|
||||
i = ((match == 0) ? erase(i) : (i+1));
|
||||
}
|
||||
}
|
55
src/branch.hpp
Normal file
55
src/branch.hpp
Normal file
|
@ -0,0 +1,55 @@
|
|||
/*
|
||||
ISC License
|
||||
|
||||
Copyright (c) 2018, Antonio SJ Musumeci <trapexit@spawn.link>
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
struct Branch
|
||||
{
|
||||
enum Mode
|
||||
{
|
||||
INVALID,
|
||||
RO,
|
||||
RW,
|
||||
NW
|
||||
};
|
||||
|
||||
Mode mode;
|
||||
std::string path;
|
||||
|
||||
bool ro(void) const;
|
||||
bool ro_or_nw(void) const;
|
||||
};
|
||||
|
||||
class Branches : public std::vector<Branch>
|
||||
{
|
||||
public:
|
||||
std::string to_string(const bool mode_ = false) const;
|
||||
|
||||
void to_paths(std::vector<std::string> &vec_) const;
|
||||
|
||||
public:
|
||||
void set(const std::string &str_);
|
||||
void add_begin(const std::string &str_);
|
||||
void add_end(const std::string &str_);
|
||||
void erase_begin(void);
|
||||
void erase_end(void);
|
||||
void erase_fnmatch(const std::string &str_);
|
||||
};
|
|
@ -68,7 +68,7 @@ _chmod_loop(const vector<const string*> &basepaths,
|
|||
static
|
||||
int
|
||||
_chmod(Policy::Func::Action actionFunc,
|
||||
const vector<string> &srcmounts,
|
||||
const Branches &branches_,
|
||||
const uint64_t minfreespace,
|
||||
const char *fusepath,
|
||||
const mode_t mode)
|
||||
|
@ -76,7 +76,7 @@ _chmod(Policy::Func::Action actionFunc,
|
|||
int rv;
|
||||
vector<const string*> basepaths;
|
||||
|
||||
rv = actionFunc(srcmounts,fusepath,minfreespace,basepaths);
|
||||
rv = actionFunc(branches_,fusepath,minfreespace,basepaths);
|
||||
if(rv == -1)
|
||||
return -errno;
|
||||
|
||||
|
@ -94,10 +94,10 @@ namespace mergerfs
|
|||
const fuse_context *fc = fuse_get_context();
|
||||
const Config &config = Config::get(fc);
|
||||
const ugid::Set ugid(fc->uid,fc->gid);
|
||||
const rwlock::ReadGuard readlock(&config.srcmountslock);
|
||||
const rwlock::ReadGuard readlock(&config.branches_lock);
|
||||
|
||||
return _chmod(config.chmod,
|
||||
config.srcmounts,
|
||||
config.branches,
|
||||
config.minfreespace,
|
||||
fusepath,
|
||||
mode);
|
||||
|
|
|
@ -71,7 +71,7 @@ _chown_loop(const vector<const string*> &basepaths,
|
|||
static
|
||||
int
|
||||
_chown(Policy::Func::Action actionFunc,
|
||||
const vector<string> &srcmounts,
|
||||
const Branches &branches_,
|
||||
const uint64_t minfreespace,
|
||||
const char *fusepath,
|
||||
const uid_t uid,
|
||||
|
@ -80,7 +80,7 @@ _chown(Policy::Func::Action actionFunc,
|
|||
int rv;
|
||||
vector<const string*> basepaths;
|
||||
|
||||
rv = actionFunc(srcmounts,fusepath,minfreespace,basepaths);
|
||||
rv = actionFunc(branches_,fusepath,minfreespace,basepaths);
|
||||
if(rv == -1)
|
||||
return -errno;
|
||||
|
||||
|
@ -99,10 +99,10 @@ namespace mergerfs
|
|||
const fuse_context *fc = fuse_get_context();
|
||||
const Config &config = Config::get(fc);
|
||||
const ugid::Set ugid(fc->uid,fc->gid);
|
||||
const rwlock::ReadGuard readlock(&config.srcmountslock);
|
||||
const rwlock::ReadGuard readlock(&config.branches_lock);
|
||||
|
||||
return _chown(config.chown,
|
||||
config.srcmounts,
|
||||
config.branches,
|
||||
config.minfreespace,
|
||||
fusepath,
|
||||
uid,
|
||||
|
|
|
@ -35,8 +35,8 @@ namespace mergerfs
|
|||
{
|
||||
Config::Config()
|
||||
: destmount(),
|
||||
srcmounts(),
|
||||
srcmountslock(),
|
||||
branches(),
|
||||
branches_lock(),
|
||||
minfreespace(MINFREESPACE_DEFAULT),
|
||||
moveonenospc(false),
|
||||
direct_io(false),
|
||||
|
@ -70,9 +70,9 @@ namespace mergerfs
|
|||
POLICYINIT(utimens),
|
||||
controlfile("/.mergerfs")
|
||||
{
|
||||
pthread_rwlock_init(&srcmountslock,NULL);
|
||||
pthread_rwlock_init(&branches_lock,NULL);
|
||||
|
||||
set_category_policy("action","all");
|
||||
set_category_policy("action","epall");
|
||||
set_category_policy("create","epmfs");
|
||||
set_category_policy("search","ff");
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "branch.hpp"
|
||||
#include "fusefunc.hpp"
|
||||
#include "policy.hpp"
|
||||
|
||||
|
@ -42,8 +43,8 @@ namespace mergerfs
|
|||
|
||||
public:
|
||||
std::string destmount;
|
||||
std::vector<std::string> srcmounts;
|
||||
mutable pthread_rwlock_t srcmountslock;
|
||||
Branches branches;
|
||||
mutable pthread_rwlock_t branches_lock;
|
||||
uint64_t minfreespace;
|
||||
bool moveonenospc;
|
||||
bool direct_io;
|
||||
|
|
|
@ -73,7 +73,7 @@ static
|
|||
int
|
||||
_create(Policy::Func::Search searchFunc,
|
||||
Policy::Func::Create createFunc,
|
||||
const vector<string> &srcmounts,
|
||||
const Branches &branches_,
|
||||
const uint64_t minfreespace,
|
||||
const char *fusepath,
|
||||
const mode_t mode,
|
||||
|
@ -89,11 +89,11 @@ _create(Policy::Func::Search searchFunc,
|
|||
|
||||
fusedirpath = fs::path::dirname(fusepath);
|
||||
|
||||
rv = searchFunc(srcmounts,fusedirpath,minfreespace,existingpaths);
|
||||
rv = searchFunc(branches_,fusedirpath,minfreespace,existingpaths);
|
||||
if(rv == -1)
|
||||
return -errno;
|
||||
|
||||
rv = createFunc(srcmounts,fusedirpath,minfreespace,createpaths);
|
||||
rv = createFunc(branches_,fusedirpath,minfreespace,createpaths);
|
||||
if(rv == -1)
|
||||
return -errno;
|
||||
|
||||
|
@ -118,11 +118,11 @@ namespace mergerfs
|
|||
const fuse_context *fc = fuse_get_context();
|
||||
const Config &config = Config::get(fc);
|
||||
const ugid::Set ugid(fc->uid,fc->gid);
|
||||
const rwlock::ReadGuard readlock(&config.srcmountslock);
|
||||
const rwlock::ReadGuard readlock(&config.branches_lock);
|
||||
|
||||
return _create(config.getattr,
|
||||
config.create,
|
||||
config.srcmounts,
|
||||
config.branches,
|
||||
config.minfreespace,
|
||||
fusepath,
|
||||
mode,
|
||||
|
|
14
src/fs.cpp
14
src/fs.cpp
|
@ -81,15 +81,15 @@ namespace fs
|
|||
}
|
||||
|
||||
void
|
||||
findallfiles(const vector<string> &srcmounts,
|
||||
findallfiles(const vector<string> &basepaths,
|
||||
const char *fusepath,
|
||||
vector<string> &paths)
|
||||
{
|
||||
string fullpath;
|
||||
|
||||
for(size_t i = 0, ei = srcmounts.size(); i != ei; i++)
|
||||
for(size_t i = 0, ei = basepaths.size(); i != ei; i++)
|
||||
{
|
||||
fs::path::make(&srcmounts[i],fusepath,fullpath);
|
||||
fs::path::make(&basepaths[i],fusepath,fullpath);
|
||||
|
||||
if(!fs::exists(fullpath))
|
||||
continue;
|
||||
|
@ -99,7 +99,7 @@ namespace fs
|
|||
}
|
||||
|
||||
int
|
||||
findonfs(const vector<string> &srcmounts,
|
||||
findonfs(const vector<string> &basepaths,
|
||||
const string &fusepath,
|
||||
const int fd,
|
||||
string &basepath)
|
||||
|
@ -114,9 +114,9 @@ namespace fs
|
|||
return -1;
|
||||
|
||||
dev = st.st_dev;
|
||||
for(size_t i = 0, ei = srcmounts.size(); i != ei; i++)
|
||||
for(size_t i = 0, ei = basepaths.size(); i != ei; i++)
|
||||
{
|
||||
fs::path::make(&srcmounts[i],fusepath,fullpath);
|
||||
fs::path::make(&basepaths[i],fusepath,fullpath);
|
||||
|
||||
rv = fs::lstat(fullpath,st);
|
||||
if(rv == -1)
|
||||
|
@ -125,7 +125,7 @@ namespace fs
|
|||
if(st.st_dev != dev)
|
||||
continue;
|
||||
|
||||
basepath = srcmounts[i];
|
||||
basepath = basepaths[i];
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -36,11 +36,11 @@ namespace fs
|
|||
int spaceused(const string *path_,
|
||||
uint64_t *spaceavail_);
|
||||
|
||||
void findallfiles(const vector<string> &srcmounts,
|
||||
void findallfiles(const vector<string> &basepaths,
|
||||
const char *fusepath,
|
||||
vector<string> &paths);
|
||||
|
||||
int findonfs(const vector<string> &srcmounts,
|
||||
int findonfs(const vector<string> &basepaths,
|
||||
const string &fusepath,
|
||||
const int fd,
|
||||
string &basepath);
|
||||
|
|
|
@ -27,25 +27,16 @@ using std::vector;
|
|||
namespace fs
|
||||
{
|
||||
void
|
||||
glob(const vector<string> &patterns_,
|
||||
vector<string> &strs_)
|
||||
glob(const string &pattern_,
|
||||
vector<string> &strs_)
|
||||
{
|
||||
int flags;
|
||||
size_t veclen;
|
||||
glob_t gbuf = {0};
|
||||
|
||||
veclen = patterns_.size();
|
||||
if(veclen == 0)
|
||||
return;
|
||||
|
||||
flags = GLOB_NOCHECK;
|
||||
::glob(patterns_[0].c_str(),flags,NULL,&gbuf);
|
||||
::glob(pattern_.c_str(),flags,NULL,&gbuf);
|
||||
|
||||
flags = GLOB_APPEND|GLOB_NOCHECK;
|
||||
for(size_t i = 1; i < veclen; i++)
|
||||
::glob(patterns_[i].c_str(),flags,NULL,&gbuf);
|
||||
|
||||
for(size_t i = 0; i < gbuf.gl_pathc; ++i)
|
||||
for(size_t i = 0; i < gbuf.gl_pathc; i++)
|
||||
strs_.push_back(gbuf.gl_pathv[i]);
|
||||
|
||||
::globfree(&gbuf);
|
||||
|
|
|
@ -23,6 +23,6 @@ namespace fs
|
|||
using std::vector;
|
||||
|
||||
void
|
||||
glob(const vector<string> &patterns_,
|
||||
vector<string> &strs_);
|
||||
glob(const string &pattern_,
|
||||
vector<string> &strs_);
|
||||
}
|
||||
|
|
|
@ -47,22 +47,4 @@ namespace fs
|
|||
|
||||
return rv;
|
||||
}
|
||||
|
||||
int
|
||||
info(const string *basepath_,
|
||||
const char *relpath_,
|
||||
fs::info_t *info_)
|
||||
{
|
||||
int rv;
|
||||
string fullpath;
|
||||
struct stat st;
|
||||
|
||||
fullpath = fs::path::make(basepath_,relpath_);
|
||||
|
||||
rv = fs::lstat(fullpath,st);
|
||||
if(rv == -1)
|
||||
return -1;
|
||||
|
||||
return fs::info(basepath_,info_);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,11 +24,6 @@
|
|||
|
||||
namespace fs
|
||||
{
|
||||
int
|
||||
info(const std::string *basepath_,
|
||||
const char *relpath_,
|
||||
fs::info_t *info_);
|
||||
|
||||
int
|
||||
info(const std::string *path_,
|
||||
fs::info_t *info_);
|
||||
|
|
|
@ -60,7 +60,7 @@ _getattr_controlfile(struct stat &st)
|
|||
static
|
||||
int
|
||||
_getattr(Policy::Func::Search searchFunc,
|
||||
const vector<string> &srcmounts,
|
||||
const Branches &branches_,
|
||||
const uint64_t minfreespace,
|
||||
const char *fusepath,
|
||||
struct stat &st,
|
||||
|
@ -71,7 +71,7 @@ _getattr(Policy::Func::Search searchFunc,
|
|||
string fullpath;
|
||||
vector<const string*> basepaths;
|
||||
|
||||
rv = searchFunc(srcmounts,fusepath,minfreespace,basepaths);
|
||||
rv = searchFunc(branches_,fusepath,minfreespace,basepaths);
|
||||
if(rv == -1)
|
||||
return -errno;
|
||||
|
||||
|
@ -104,10 +104,10 @@ namespace mergerfs
|
|||
return _getattr_controlfile(*st);
|
||||
|
||||
const ugid::Set ugid(fc->uid,fc->gid);
|
||||
const rwlock::ReadGuard readlock(&config.srcmountslock);
|
||||
const rwlock::ReadGuard readlock(&config.branches_lock);
|
||||
|
||||
return _getattr(config.getattr,
|
||||
config.srcmounts,
|
||||
config.branches,
|
||||
config.minfreespace,
|
||||
fusepath,
|
||||
*st,
|
||||
|
|
|
@ -105,7 +105,15 @@ void
|
|||
_getxattr_controlfile_srcmounts(const Config &config,
|
||||
string &attrvalue)
|
||||
{
|
||||
attrvalue = str::join(config.srcmounts,':');
|
||||
attrvalue = config.branches.to_string();
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
_getxattr_controlfile_branches(const Config &config,
|
||||
string &attrvalue)
|
||||
{
|
||||
attrvalue = config.branches.to_string(true);
|
||||
}
|
||||
|
||||
static
|
||||
|
@ -216,6 +224,8 @@ _getxattr_controlfile(const Config &config,
|
|||
case 3:
|
||||
if(attr[2] == "srcmounts")
|
||||
_getxattr_controlfile_srcmounts(config,attrvalue);
|
||||
else if(attr[2] == "branches")
|
||||
_getxattr_controlfile_branches(config,attrvalue);
|
||||
else if(attr[2] == "minfreespace")
|
||||
_getxattr_controlfile_uint64_t(config.minfreespace,attrvalue);
|
||||
else if(attr[2] == "moveonenospc")
|
||||
|
@ -289,15 +299,18 @@ _getxattr_from_string(char *destbuf,
|
|||
|
||||
static
|
||||
int
|
||||
_getxattr_user_mergerfs_allpaths(const vector<string> &srcmounts,
|
||||
const char *fusepath,
|
||||
char *buf,
|
||||
const size_t count)
|
||||
_getxattr_user_mergerfs_allpaths(const Branches &branches_,
|
||||
const char *fusepath,
|
||||
char *buf,
|
||||
const size_t count)
|
||||
{
|
||||
string concated;
|
||||
vector<string> paths;
|
||||
vector<string> branches;
|
||||
|
||||
fs::findallfiles(srcmounts,fusepath,paths);
|
||||
branches_.to_paths(branches);
|
||||
|
||||
fs::findallfiles(branches,fusepath,paths);
|
||||
|
||||
concated = str::join(paths,'\0');
|
||||
|
||||
|
@ -309,7 +322,7 @@ int
|
|||
_getxattr_user_mergerfs(const string &basepath,
|
||||
const char *fusepath,
|
||||
const string &fullpath,
|
||||
const vector<string> &srcmounts,
|
||||
const Branches &branches_,
|
||||
const char *attrname,
|
||||
char *buf,
|
||||
const size_t count)
|
||||
|
@ -325,7 +338,7 @@ _getxattr_user_mergerfs(const string &basepath,
|
|||
else if(attr[2] == "fullpath")
|
||||
return _getxattr_from_string(buf,count,fullpath);
|
||||
else if(attr[2] == "allpaths")
|
||||
return _getxattr_user_mergerfs_allpaths(srcmounts,fusepath,buf,count);
|
||||
return _getxattr_user_mergerfs_allpaths(branches_,fusepath,buf,count);
|
||||
|
||||
return -ENOATTR;
|
||||
}
|
||||
|
@ -333,7 +346,7 @@ _getxattr_user_mergerfs(const string &basepath,
|
|||
static
|
||||
int
|
||||
_getxattr(Policy::Func::Search searchFunc,
|
||||
const vector<string> &srcmounts,
|
||||
const Branches &branches_,
|
||||
const size_t minfreespace,
|
||||
const char *fusepath,
|
||||
const char *attrname,
|
||||
|
@ -344,14 +357,14 @@ _getxattr(Policy::Func::Search searchFunc,
|
|||
string fullpath;
|
||||
vector<const string*> basepaths;
|
||||
|
||||
rv = searchFunc(srcmounts,fusepath,minfreespace,basepaths);
|
||||
rv = searchFunc(branches_,fusepath,minfreespace,basepaths);
|
||||
if(rv == -1)
|
||||
return -errno;
|
||||
|
||||
fs::path::make(basepaths[0],fusepath,fullpath);
|
||||
|
||||
if(str::isprefix(attrname,"user.mergerfs."))
|
||||
rv = _getxattr_user_mergerfs(*basepaths[0],fusepath,fullpath,srcmounts,attrname,buf,count);
|
||||
rv = _getxattr_user_mergerfs(*basepaths[0],fusepath,fullpath,branches_,attrname,buf,count);
|
||||
else
|
||||
rv = _lgetxattr(fullpath,attrname,buf,count);
|
||||
|
||||
|
@ -385,10 +398,10 @@ namespace mergerfs
|
|||
return -config.xattr;
|
||||
|
||||
const ugid::Set ugid(fc->uid,fc->gid);
|
||||
const rwlock::ReadGuard readlock(&config.srcmountslock);
|
||||
const rwlock::ReadGuard readlock(&config.branches_lock);
|
||||
|
||||
return _getxattr(config.getxattr,
|
||||
config.srcmounts,
|
||||
config.branches,
|
||||
config.minfreespace,
|
||||
fusepath,
|
||||
attrname,
|
||||
|
|
|
@ -69,7 +69,7 @@ _ioctl_file(fuse_file_info *ffi,
|
|||
static
|
||||
int
|
||||
_ioctl_dir_base(Policy::Func::Search searchFunc,
|
||||
const vector<string> &srcmounts,
|
||||
const Branches &branches_,
|
||||
const uint64_t minfreespace,
|
||||
const char *fusepath,
|
||||
const unsigned long cmd,
|
||||
|
@ -80,7 +80,7 @@ _ioctl_dir_base(Policy::Func::Search searchFunc,
|
|||
string fullpath;
|
||||
vector<const string*> basepaths;
|
||||
|
||||
rv = searchFunc(srcmounts,fusepath,minfreespace,basepaths);
|
||||
rv = searchFunc(branches_,fusepath,minfreespace,basepaths);
|
||||
if(rv == -1)
|
||||
return -errno;
|
||||
|
||||
|
@ -108,10 +108,10 @@ _ioctl_dir(fuse_file_info *ffi,
|
|||
const fuse_context *fc = fuse_get_context();
|
||||
const Config &config = Config::get(fc);
|
||||
const ugid::Set ugid(fc->uid,fc->gid);
|
||||
const rwlock::ReadGuard readlock(&config.srcmountslock);
|
||||
const rwlock::ReadGuard readlock(&config.branches_lock);
|
||||
|
||||
return _ioctl_dir_base(config.getattr,
|
||||
config.srcmounts,
|
||||
config.branches,
|
||||
config.minfreespace,
|
||||
di->fusepath.c_str(),
|
||||
cmd,
|
||||
|
|
32
src/link.cpp
32
src/link.cpp
|
@ -83,7 +83,7 @@ static
|
|||
int
|
||||
_link_create_path(Policy::Func::Search searchFunc,
|
||||
Policy::Func::Action actionFunc,
|
||||
const vector<string> &srcmounts,
|
||||
const Branches &branches_,
|
||||
const uint64_t minfreespace,
|
||||
const char *oldfusepath,
|
||||
const char *newfusepath)
|
||||
|
@ -93,13 +93,13 @@ _link_create_path(Policy::Func::Search searchFunc,
|
|||
vector<const string*> oldbasepaths;
|
||||
vector<const string*> newbasepaths;
|
||||
|
||||
rv = actionFunc(srcmounts,oldfusepath,minfreespace,oldbasepaths);
|
||||
rv = actionFunc(branches_,oldfusepath,minfreespace,oldbasepaths);
|
||||
if(rv == -1)
|
||||
return -errno;
|
||||
|
||||
newfusedirpath = fs::path::dirname(newfusepath);
|
||||
|
||||
rv = searchFunc(srcmounts,newfusedirpath,minfreespace,newbasepaths);
|
||||
rv = searchFunc(branches_,newfusedirpath,minfreespace,newbasepaths);
|
||||
if(rv == -1)
|
||||
return -errno;
|
||||
|
||||
|
@ -112,7 +112,7 @@ static
|
|||
int
|
||||
_clonepath_if_would_create(Policy::Func::Search searchFunc,
|
||||
Policy::Func::Create createFunc,
|
||||
const vector<string> &srcmounts,
|
||||
const Branches &branches_,
|
||||
const uint64_t minfreespace,
|
||||
const string &oldbasepath,
|
||||
const char *oldfusepath,
|
||||
|
@ -124,14 +124,14 @@ _clonepath_if_would_create(Policy::Func::Search searchFunc,
|
|||
|
||||
newfusedirpath = fs::path::dirname(newfusepath);
|
||||
|
||||
rv = createFunc(srcmounts,newfusedirpath,minfreespace,newbasepath);
|
||||
rv = createFunc(branches_,newfusedirpath,minfreespace,newbasepath);
|
||||
if(rv == -1)
|
||||
return -1;
|
||||
|
||||
if(oldbasepath != *newbasepath[0])
|
||||
return (errno=EXDEV,-1);
|
||||
|
||||
rv = searchFunc(srcmounts,newfusedirpath,minfreespace,newbasepath);
|
||||
rv = searchFunc(branches_,newfusedirpath,minfreespace,newbasepath);
|
||||
if(rv == -1)
|
||||
return -1;
|
||||
|
||||
|
@ -142,7 +142,7 @@ static
|
|||
int
|
||||
_link_preserve_path_core(Policy::Func::Search searchFunc,
|
||||
Policy::Func::Create createFunc,
|
||||
const vector<string> &srcmounts,
|
||||
const Branches &branches_,
|
||||
const uint64_t minfreespace,
|
||||
const string &oldbasepath,
|
||||
const char *oldfusepath,
|
||||
|
@ -160,7 +160,7 @@ _link_preserve_path_core(Policy::Func::Search searchFunc,
|
|||
if((rv == -1) && (errno == ENOENT))
|
||||
{
|
||||
rv = _clonepath_if_would_create(searchFunc,createFunc,
|
||||
srcmounts,minfreespace,
|
||||
branches_,minfreespace,
|
||||
oldbasepath,
|
||||
oldfusepath,newfusepath);
|
||||
if(rv != -1)
|
||||
|
@ -174,7 +174,7 @@ static
|
|||
int
|
||||
_link_preserve_path_loop(Policy::Func::Search searchFunc,
|
||||
Policy::Func::Create createFunc,
|
||||
const vector<string> &srcmounts,
|
||||
const Branches &branches_,
|
||||
const uint64_t minfreespace,
|
||||
const char *oldfusepath,
|
||||
const char *newfusepath,
|
||||
|
@ -186,7 +186,7 @@ _link_preserve_path_loop(Policy::Func::Search searchFunc,
|
|||
for(size_t i = 0, ei = oldbasepaths.size(); i != ei; i++)
|
||||
{
|
||||
error = _link_preserve_path_core(searchFunc,createFunc,
|
||||
srcmounts,minfreespace,
|
||||
branches_,minfreespace,
|
||||
*oldbasepaths[i],
|
||||
oldfusepath,newfusepath,
|
||||
error);
|
||||
|
@ -200,7 +200,7 @@ int
|
|||
_link_preserve_path(Policy::Func::Search searchFunc,
|
||||
Policy::Func::Action actionFunc,
|
||||
Policy::Func::Create createFunc,
|
||||
const vector<string> &srcmounts,
|
||||
const Branches &branches_,
|
||||
const uint64_t minfreespace,
|
||||
const char *oldfusepath,
|
||||
const char *newfusepath)
|
||||
|
@ -208,12 +208,12 @@ _link_preserve_path(Policy::Func::Search searchFunc,
|
|||
int rv;
|
||||
vector<const string*> oldbasepaths;
|
||||
|
||||
rv = actionFunc(srcmounts,oldfusepath,minfreespace,oldbasepaths);
|
||||
rv = actionFunc(branches_,oldfusepath,minfreespace,oldbasepaths);
|
||||
if(rv == -1)
|
||||
return -errno;
|
||||
|
||||
return _link_preserve_path_loop(searchFunc,createFunc,
|
||||
srcmounts,minfreespace,
|
||||
branches_,minfreespace,
|
||||
oldfusepath,newfusepath,
|
||||
oldbasepaths);
|
||||
}
|
||||
|
@ -229,20 +229,20 @@ namespace mergerfs
|
|||
const fuse_context *fc = fuse_get_context();
|
||||
const Config &config = Config::get(fc);
|
||||
const ugid::Set ugid(fc->uid,fc->gid);
|
||||
const rwlock::ReadGuard readlock(&config.srcmountslock);
|
||||
const rwlock::ReadGuard readlock(&config.branches_lock);
|
||||
|
||||
if(config.create->path_preserving() && !config.ignorepponrename)
|
||||
return _link_preserve_path(config.getattr,
|
||||
config.link,
|
||||
config.create,
|
||||
config.srcmounts,
|
||||
config.branches,
|
||||
config.minfreespace,
|
||||
from,
|
||||
to);
|
||||
|
||||
return _link_create_path(config.link,
|
||||
config.create,
|
||||
config.srcmounts,
|
||||
config.branches,
|
||||
config.minfreespace,
|
||||
from,
|
||||
to);
|
||||
|
|
|
@ -44,6 +44,7 @@ _listxattr_controlfile(char *list,
|
|||
const vector<string> strs =
|
||||
buildvector<string>
|
||||
("user.mergerfs.srcmounts")
|
||||
("user.mergerfs.branches")
|
||||
("user.mergerfs.minfreespace")
|
||||
("user.mergerfs.moveonenospc")
|
||||
("user.mergerfs.dropcacheonclose")
|
||||
|
@ -80,7 +81,7 @@ _listxattr_controlfile(char *list,
|
|||
static
|
||||
int
|
||||
_listxattr(Policy::Func::Search searchFunc,
|
||||
const vector<string> &srcmounts,
|
||||
const Branches &branches_,
|
||||
const uint64_t minfreespace,
|
||||
const char *fusepath,
|
||||
char *list,
|
||||
|
@ -90,7 +91,7 @@ _listxattr(Policy::Func::Search searchFunc,
|
|||
string fullpath;
|
||||
vector<const string*> basepaths;
|
||||
|
||||
rv = searchFunc(srcmounts,fusepath,minfreespace,basepaths);
|
||||
rv = searchFunc(branches_,fusepath,minfreespace,basepaths);
|
||||
if(rv == -1)
|
||||
return -errno;
|
||||
|
||||
|
@ -127,10 +128,10 @@ namespace mergerfs
|
|||
}
|
||||
|
||||
const ugid::Set ugid(fc->uid,fc->gid);
|
||||
const rwlock::ReadGuard readlock(&config.srcmountslock);
|
||||
const rwlock::ReadGuard readlock(&config.branches_lock);
|
||||
|
||||
return _listxattr(config.listxattr,
|
||||
config.srcmounts,
|
||||
config.branches,
|
||||
config.minfreespace,
|
||||
fusepath,
|
||||
list,
|
||||
|
|
|
@ -94,7 +94,7 @@ static
|
|||
int
|
||||
_mkdir(Policy::Func::Search searchFunc,
|
||||
Policy::Func::Create createFunc,
|
||||
const vector<string> &srcmounts,
|
||||
const Branches &branches_,
|
||||
const uint64_t minfreespace,
|
||||
const char *fusepath,
|
||||
const mode_t mode,
|
||||
|
@ -107,11 +107,11 @@ _mkdir(Policy::Func::Search searchFunc,
|
|||
|
||||
fusedirpath = fs::path::dirname(fusepath);
|
||||
|
||||
rv = searchFunc(srcmounts,fusedirpath,minfreespace,existingpaths);
|
||||
rv = searchFunc(branches_,fusedirpath,minfreespace,existingpaths);
|
||||
if(rv == -1)
|
||||
return -errno;
|
||||
|
||||
rv = createFunc(srcmounts,fusedirpath,minfreespace,createpaths);
|
||||
rv = createFunc(branches_,fusedirpath,minfreespace,createpaths);
|
||||
if(rv == -1)
|
||||
return -errno;
|
||||
|
||||
|
@ -130,11 +130,11 @@ namespace mergerfs
|
|||
const fuse_context *fc = fuse_get_context();
|
||||
const Config &config = Config::get(fc);
|
||||
const ugid::Set ugid(fc->uid,fc->gid);
|
||||
const rwlock::ReadGuard readlock(&config.srcmountslock);
|
||||
const rwlock::ReadGuard readlock(&config.branches_lock);
|
||||
|
||||
return _mkdir(config.getattr,
|
||||
config.mkdir,
|
||||
config.srcmounts,
|
||||
config.branches,
|
||||
config.minfreespace,
|
||||
fusepath,
|
||||
mode,
|
||||
|
|
|
@ -98,7 +98,7 @@ static
|
|||
int
|
||||
_mknod(Policy::Func::Search searchFunc,
|
||||
Policy::Func::Create createFunc,
|
||||
const vector<string> &srcmounts,
|
||||
const Branches &branches_,
|
||||
const uint64_t minfreespace,
|
||||
const char *fusepath,
|
||||
const mode_t mode,
|
||||
|
@ -112,11 +112,11 @@ _mknod(Policy::Func::Search searchFunc,
|
|||
|
||||
fusedirpath = fs::path::dirname(fusepath);
|
||||
|
||||
rv = searchFunc(srcmounts,fusedirpath,minfreespace,existingpaths);
|
||||
rv = searchFunc(branches_,fusedirpath,minfreespace,existingpaths);
|
||||
if(rv == -1)
|
||||
return -errno;
|
||||
|
||||
rv = createFunc(srcmounts,fusedirpath,minfreespace,createpaths);
|
||||
rv = createFunc(branches_,fusedirpath,minfreespace,createpaths);
|
||||
if(rv == -1)
|
||||
return -errno;
|
||||
|
||||
|
@ -137,11 +137,11 @@ namespace mergerfs
|
|||
const fuse_context *fc = fuse_get_context();
|
||||
const Config &config = Config::get(fc);
|
||||
const ugid::Set ugid(fc->uid,fc->gid);
|
||||
const rwlock::ReadGuard readlock(&config.srcmountslock);
|
||||
const rwlock::ReadGuard readlock(&config.branches_lock);
|
||||
|
||||
return _mknod(config.getattr,
|
||||
config.mknod,
|
||||
config.srcmounts,
|
||||
config.branches,
|
||||
config.minfreespace,
|
||||
fusepath,
|
||||
mode,
|
||||
|
|
|
@ -62,7 +62,7 @@ _open_core(const string *basepath_,
|
|||
static
|
||||
int
|
||||
_open(Policy::Func::Search searchFunc_,
|
||||
const vector<string> &srcmounts_,
|
||||
const Branches &branches_,
|
||||
const uint64_t minfreespace_,
|
||||
const char *fusepath_,
|
||||
const int flags_,
|
||||
|
@ -72,7 +72,7 @@ _open(Policy::Func::Search searchFunc_,
|
|||
int rv;
|
||||
vector<const string*> basepaths;
|
||||
|
||||
rv = searchFunc_(srcmounts_,fusepath_,minfreespace_,basepaths);
|
||||
rv = searchFunc_(branches_,fusepath_,minfreespace_,basepaths);
|
||||
if(rv == -1)
|
||||
return -errno;
|
||||
|
||||
|
@ -90,10 +90,10 @@ namespace mergerfs
|
|||
const fuse_context *fc = fuse_get_context();
|
||||
const Config &config = Config::get(fc);
|
||||
const ugid::Set ugid(fc->uid,fc->gid);
|
||||
const rwlock::ReadGuard readlock(&config.srcmountslock);
|
||||
const rwlock::ReadGuard readlock(&config.branches_lock);
|
||||
|
||||
return _open(config.open,
|
||||
config.srcmounts,
|
||||
config.branches,
|
||||
config.minfreespace,
|
||||
fusepath_,
|
||||
ffi_->flags,
|
||||
|
|
|
@ -73,14 +73,18 @@ set_kv_option(fuse_args &args,
|
|||
|
||||
static
|
||||
void
|
||||
set_fsname(fuse_args &args,
|
||||
const vector<string> &srcmounts)
|
||||
set_fsname(fuse_args &args,
|
||||
const Branches &branches_)
|
||||
{
|
||||
if(srcmounts.size() > 0)
|
||||
vector<string> branches;
|
||||
|
||||
branches_.to_paths(branches);
|
||||
|
||||
if(branches.size() > 0)
|
||||
{
|
||||
std::string fsname;
|
||||
|
||||
fsname = str::remove_common_prefix_and_join(srcmounts,':');
|
||||
fsname = str::remove_common_prefix_and_join(branches,':');
|
||||
|
||||
set_kv_option(args,"fsname",fsname);
|
||||
}
|
||||
|
@ -257,16 +261,10 @@ process_opt(Config &config,
|
|||
|
||||
static
|
||||
int
|
||||
process_srcmounts(const char *arg,
|
||||
Config &config)
|
||||
process_branches(const char *arg,
|
||||
Config &config)
|
||||
{
|
||||
vector<string> paths;
|
||||
|
||||
str::split(paths,arg,':');
|
||||
|
||||
fs::glob(paths,config.srcmounts);
|
||||
|
||||
fs::realpathize(config.srcmounts);
|
||||
config.branches.set(arg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -356,8 +354,8 @@ option_processor(void *data,
|
|||
break;
|
||||
|
||||
case FUSE_OPT_KEY_NONOPT:
|
||||
rv = config.srcmounts.empty() ?
|
||||
process_srcmounts(arg,config) :
|
||||
rv = config.branches.empty() ?
|
||||
process_branches(arg,config) :
|
||||
process_destmounts(arg,config);
|
||||
break;
|
||||
|
||||
|
@ -406,7 +404,7 @@ namespace mergerfs
|
|||
opts,
|
||||
::option_processor);
|
||||
|
||||
set_fsname(args,config.srcmounts);
|
||||
set_fsname(args,config.branches);
|
||||
set_subtype(args);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "branch.hpp"
|
||||
#include "category.hpp"
|
||||
#include "fs.hpp"
|
||||
|
||||
|
@ -65,7 +66,7 @@ namespace mergerfs
|
|||
typedef const strvec cstrvec;
|
||||
typedef const Category::Enum::Type CType;
|
||||
|
||||
typedef int (*Ptr)(CType,cstrvec &,const char *,cuint64_t,cstrptrvec &);
|
||||
typedef int (*Ptr)(CType,const Branches &,const char *,cuint64_t,cstrptrvec &);
|
||||
|
||||
template <CType T>
|
||||
class Base
|
||||
|
@ -76,13 +77,13 @@ namespace mergerfs
|
|||
{}
|
||||
|
||||
int
|
||||
operator()(cstrvec &b,const char *c,cuint64_t d,cstrptrvec &e)
|
||||
operator()(const Branches &b,const char *c,cuint64_t d,cstrptrvec &e)
|
||||
{
|
||||
return func(T,b,c,d,e);
|
||||
}
|
||||
|
||||
int
|
||||
operator()(cstrvec &b,const string &c,cuint64_t d,cstrptrvec &e)
|
||||
operator()(const Branches &b,const string &c,cuint64_t d,cstrptrvec &e)
|
||||
{
|
||||
return func(T,b,c.c_str(),d,e);
|
||||
}
|
||||
|
@ -95,21 +96,21 @@ namespace mergerfs
|
|||
typedef Base<Category::Enum::create> Create;
|
||||
typedef Base<Category::Enum::search> Search;
|
||||
|
||||
static int invalid(CType,cstrvec&,const char *,cuint64_t,cstrptrvec&);
|
||||
static int all(CType,cstrvec&,const char*,cuint64_t,cstrptrvec&);
|
||||
static int epall(CType,cstrvec&,const char*,cuint64_t,cstrptrvec&);
|
||||
static int epff(CType,cstrvec&,const char *,cuint64_t,cstrptrvec&);
|
||||
static int eplfs(CType,cstrvec&,const char *,cuint64_t,cstrptrvec&);
|
||||
static int eplus(CType,cstrvec&,const char *,cuint64_t,cstrptrvec&);
|
||||
static int epmfs(CType,cstrvec&,const char *,cuint64_t,cstrptrvec&);
|
||||
static int eprand(CType,cstrvec&,const char *,cuint64_t,cstrptrvec&);
|
||||
static int erofs(CType,cstrvec&,const char *,cuint64_t,cstrptrvec&);
|
||||
static int ff(CType,cstrvec&,const char *,cuint64_t,cstrptrvec&);
|
||||
static int lfs(CType,cstrvec&,const char *,cuint64_t,cstrptrvec&);
|
||||
static int lus(CType,cstrvec&,const char *,cuint64_t,cstrptrvec&);
|
||||
static int mfs(CType,cstrvec&,const char *,cuint64_t,cstrptrvec&);
|
||||
static int newest(CType,cstrvec&,const char *,cuint64_t,cstrptrvec&);
|
||||
static int rand(CType,cstrvec&,const char *,cuint64_t,cstrptrvec&);
|
||||
static int invalid(CType,const Branches&,const char *,cuint64_t,cstrptrvec&);
|
||||
static int all(CType,const Branches&,const char*,cuint64_t,cstrptrvec&);
|
||||
static int epall(CType,const Branches&,const char*,cuint64_t,cstrptrvec&);
|
||||
static int epff(CType,const Branches&,const char *,cuint64_t,cstrptrvec&);
|
||||
static int eplfs(CType,const Branches&,const char *,cuint64_t,cstrptrvec&);
|
||||
static int eplus(CType,const Branches&,const char *,cuint64_t,cstrptrvec&);
|
||||
static int epmfs(CType,const Branches&,const char *,cuint64_t,cstrptrvec&);
|
||||
static int eprand(CType,const Branches&,const char *,cuint64_t,cstrptrvec&);
|
||||
static int erofs(CType,const Branches&,const char *,cuint64_t,cstrptrvec&);
|
||||
static int ff(CType,const Branches&,const char *,cuint64_t,cstrptrvec&);
|
||||
static int lfs(CType,const Branches&,const char *,cuint64_t,cstrptrvec&);
|
||||
static int lus(CType,const Branches&,const char *,cuint64_t,cstrptrvec&);
|
||||
static int mfs(CType,const Branches&,const char *,cuint64_t,cstrptrvec&);
|
||||
static int newest(CType,const Branches&,const char *,cuint64_t,cstrptrvec&);
|
||||
static int rand(CType,const Branches&,const char *,cuint64_t,cstrptrvec&);
|
||||
};
|
||||
|
||||
private:
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include "fs_info.hpp"
|
||||
#include "fs_path.hpp"
|
||||
#include "policy.hpp"
|
||||
#include "policy_error.hpp"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
@ -26,73 +27,56 @@
|
|||
using std::string;
|
||||
using std::vector;
|
||||
|
||||
static
|
||||
int
|
||||
_all_create(const vector<string> &basepaths,
|
||||
const uint64_t minfreespace,
|
||||
vector<const string*> &paths)
|
||||
namespace all
|
||||
{
|
||||
int rv;
|
||||
fs::info_t info;
|
||||
const string *basepath;
|
||||
static
|
||||
int
|
||||
create(const Branches &branches_,
|
||||
const uint64_t minfreespace,
|
||||
vector<const string*> &paths)
|
||||
{
|
||||
int rv;
|
||||
int error;
|
||||
fs::info_t info;
|
||||
const Branch *branch;
|
||||
|
||||
for(size_t i = 0, ei = basepaths.size(); i != ei; i++)
|
||||
{
|
||||
basepath = &basepaths[i];
|
||||
error = ENOENT;
|
||||
for(size_t i = 0, ei = branches_.size(); i != ei; i++)
|
||||
{
|
||||
branch = &branches_[i];
|
||||
|
||||
rv = fs::info(basepath,&info);
|
||||
if(rv == -1)
|
||||
continue;
|
||||
if(info.readonly)
|
||||
continue;
|
||||
if(info.spaceavail < minfreespace)
|
||||
continue;
|
||||
if(branch->ro_or_nw())
|
||||
error_and_continue(error,EROFS);
|
||||
rv = fs::info(&branch->path,&info);
|
||||
if(rv == -1)
|
||||
error_and_continue(error,ENOENT);
|
||||
if(info.readonly)
|
||||
error_and_continue(error,EROFS);
|
||||
if(info.spaceavail < minfreespace)
|
||||
error_and_continue(error,ENOSPC);
|
||||
|
||||
paths.push_back(basepath);
|
||||
}
|
||||
paths.push_back(&branch->path);
|
||||
}
|
||||
|
||||
if(paths.empty())
|
||||
return (errno=ENOENT,-1);
|
||||
if(paths.empty())
|
||||
return (errno=error,-1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
_all_other(const vector<string> &basepaths,
|
||||
const char *fusepath,
|
||||
vector<const string*> &paths)
|
||||
{
|
||||
const string *basepath;
|
||||
|
||||
for(size_t i = 0, ei = basepaths.size(); i != ei; i++)
|
||||
{
|
||||
basepath = &basepaths[i];
|
||||
|
||||
if(!fs::exists(*basepath,fusepath))
|
||||
continue;
|
||||
|
||||
paths.push_back(basepath);
|
||||
}
|
||||
|
||||
if(paths.empty())
|
||||
return (errno=ENOENT,-1);
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
namespace mergerfs
|
||||
{
|
||||
int
|
||||
Policy::Func::all(const Category::Enum::Type type,
|
||||
const vector<string> &basepaths,
|
||||
const Branches &branches_,
|
||||
const char *fusepath,
|
||||
const uint64_t minfreespace,
|
||||
vector<const string*> &paths)
|
||||
{
|
||||
if(type == Category::Enum::create)
|
||||
return _all_create(basepaths,minfreespace,paths);
|
||||
return all::create(branches_,minfreespace,paths);
|
||||
|
||||
return _all_other(basepaths,fusepath,paths);
|
||||
return Policy::Func::epall(type,branches_,fusepath,minfreespace,paths);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include "fs_info.hpp"
|
||||
#include "fs_path.hpp"
|
||||
#include "policy.hpp"
|
||||
#include "policy_error.hpp"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
@ -27,74 +28,124 @@
|
|||
using std::string;
|
||||
using std::vector;
|
||||
|
||||
static
|
||||
int
|
||||
_epall_create(const vector<string> &basepaths,
|
||||
const char *fusepath,
|
||||
const uint64_t minfreespace,
|
||||
vector<const string*> &paths)
|
||||
namespace epall
|
||||
{
|
||||
int rv;
|
||||
fs::info_t info;
|
||||
const string *basepath;
|
||||
static
|
||||
int
|
||||
create(const Branches &branches_,
|
||||
const char *fusepath,
|
||||
const uint64_t minfreespace,
|
||||
vector<const string*> &paths)
|
||||
{
|
||||
int rv;
|
||||
int error;
|
||||
fs::info_t info;
|
||||
const Branch *branch;
|
||||
|
||||
for(size_t i = 0, ei = basepaths.size(); i != ei; i++)
|
||||
{
|
||||
basepath = &basepaths[i];
|
||||
error = ENOENT;
|
||||
for(size_t i = 0, ei = branches_.size(); i != ei; i++)
|
||||
{
|
||||
branch = &branches_[i];
|
||||
|
||||
rv = fs::info(basepath,fusepath,&info);
|
||||
if(rv == -1)
|
||||
continue;
|
||||
if(info.readonly)
|
||||
continue;
|
||||
if(info.spaceavail < minfreespace)
|
||||
continue;
|
||||
if(!fs::exists(branch->path,fusepath))
|
||||
error_and_continue(error,ENOENT);
|
||||
if(branch->ro_or_nw())
|
||||
error_and_continue(error,EROFS);
|
||||
rv = fs::info(&branch->path,&info);
|
||||
if(rv == -1)
|
||||
error_and_continue(error,ENOENT);
|
||||
if(info.readonly)
|
||||
error_and_continue(error,EROFS);
|
||||
if(info.spaceavail < minfreespace)
|
||||
error_and_continue(error,ENOSPC);
|
||||
|
||||
paths.push_back(basepath);
|
||||
}
|
||||
paths.push_back(&branch->path);
|
||||
}
|
||||
|
||||
if(paths.empty())
|
||||
return (errno=ENOENT,-1);
|
||||
if(paths.empty())
|
||||
return (errno=error,-1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
_epall_other(const vector<string> &basepaths,
|
||||
const char *fusepath,
|
||||
vector<const string*> &paths)
|
||||
{
|
||||
const string *basepath;
|
||||
static
|
||||
int
|
||||
action(const Branches &branches_,
|
||||
const char *fusepath,
|
||||
vector<const string*> &paths)
|
||||
{
|
||||
int rv;
|
||||
int error;
|
||||
bool readonly;
|
||||
const Branch *branch;
|
||||
|
||||
for(size_t i = 0, ei = basepaths.size(); i != ei; i++)
|
||||
{
|
||||
basepath = &basepaths[i];
|
||||
error = ENOENT;
|
||||
for(size_t i = 0, ei = branches_.size(); i != ei; i++)
|
||||
{
|
||||
branch = &branches_[i];
|
||||
|
||||
if(!fs::exists(*basepath,fusepath))
|
||||
continue;
|
||||
if(!fs::exists(branch->path,fusepath))
|
||||
error_and_continue(error,ENOENT);
|
||||
if(branch->ro())
|
||||
error_and_continue(error,EROFS);
|
||||
rv = fs::readonly(&branch->path,&readonly);
|
||||
if(rv == -1)
|
||||
error_and_continue(error,ENOENT);
|
||||
if(readonly)
|
||||
error_and_continue(error,EROFS);
|
||||
|
||||
paths.push_back(basepath);
|
||||
}
|
||||
paths.push_back(&branch->path);
|
||||
}
|
||||
|
||||
if(paths.empty())
|
||||
return (errno=ENOENT,-1);
|
||||
if(paths.empty())
|
||||
return (errno=error,-1);
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
search(const Branches &branches_,
|
||||
const char *fusepath,
|
||||
vector<const string*> &paths)
|
||||
{
|
||||
const Branch *branch;
|
||||
|
||||
for(size_t i = 0, ei = branches_.size(); i != ei; i++)
|
||||
{
|
||||
branch = &branches_[i];
|
||||
|
||||
if(!fs::exists(branch->path,fusepath))
|
||||
continue;
|
||||
|
||||
paths.push_back(&branch->path);
|
||||
}
|
||||
|
||||
if(paths.empty())
|
||||
return (errno=ENOENT,-1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
namespace mergerfs
|
||||
{
|
||||
int
|
||||
Policy::Func::epall(const Category::Enum::Type type,
|
||||
const vector<string> &basepaths,
|
||||
const Branches &branches_,
|
||||
const char *fusepath,
|
||||
const uint64_t minfreespace,
|
||||
vector<const string*> &paths)
|
||||
{
|
||||
if(type == Category::Enum::create)
|
||||
return _epall_create(basepaths,fusepath,minfreespace,paths);
|
||||
|
||||
return _epall_other(basepaths,fusepath,paths);
|
||||
switch(type)
|
||||
{
|
||||
case Category::Enum::create:
|
||||
return epall::create(branches_,fusepath,minfreespace,paths);
|
||||
case Category::Enum::action:
|
||||
return epall::action(branches_,fusepath,paths);
|
||||
case Category::Enum::search:
|
||||
default:
|
||||
return epall::search(branches_,fusepath,paths);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include "fs_info.hpp"
|
||||
#include "fs_path.hpp"
|
||||
#include "policy.hpp"
|
||||
#include "policy_error.hpp"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
@ -28,89 +29,121 @@ using std::string;
|
|||
using std::vector;
|
||||
using mergerfs::Category;
|
||||
|
||||
static
|
||||
int
|
||||
_epff_create(const vector<string> &basepaths,
|
||||
const char *fusepath,
|
||||
const uint64_t minfreespace,
|
||||
vector<const string*> &paths)
|
||||
namespace epff
|
||||
{
|
||||
int rv;
|
||||
fs::info_t info;
|
||||
const string *basepath;
|
||||
static
|
||||
int
|
||||
create(const Branches &branches_,
|
||||
const char *fusepath,
|
||||
const uint64_t minfreespace,
|
||||
vector<const string*> &paths)
|
||||
{
|
||||
int rv;
|
||||
int error;
|
||||
fs::info_t info;
|
||||
const Branch *branch;
|
||||
|
||||
for(size_t i = 0, ei = basepaths.size(); i != ei; i++)
|
||||
{
|
||||
basepath = &basepaths[i];
|
||||
error = ENOENT;
|
||||
for(size_t i = 0, ei = branches_.size(); i != ei; i++)
|
||||
{
|
||||
branch = &branches_[i];
|
||||
|
||||
rv = fs::info(basepath,fusepath,&info);
|
||||
if(rv == -1)
|
||||
continue;
|
||||
if(info.readonly)
|
||||
continue;
|
||||
if(info.spaceavail < minfreespace)
|
||||
continue;
|
||||
if(!fs::exists(branch->path,fusepath))
|
||||
error_and_continue(error,ENOENT);
|
||||
if(branch->ro_or_nw())
|
||||
error_and_continue(error,EROFS);
|
||||
rv = fs::info(&branch->path,&info);
|
||||
if(rv == -1)
|
||||
error_and_continue(error,ENOENT);
|
||||
if(info.readonly)
|
||||
error_and_continue(error,EROFS);
|
||||
if(info.spaceavail < minfreespace)
|
||||
error_and_continue(error,ENOSPC);
|
||||
|
||||
paths.push_back(basepath);
|
||||
paths.push_back(&branch->path);
|
||||
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
return (errno=ENOENT,-1);
|
||||
}
|
||||
return (errno=error,-1);
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
_epff_other(const vector<string> &basepaths,
|
||||
const char *fusepath,
|
||||
vector<const string*> &paths)
|
||||
{
|
||||
const string *basepath;
|
||||
static
|
||||
int
|
||||
action(const Branches &branches_,
|
||||
const char *fusepath,
|
||||
vector<const string*> &paths)
|
||||
{
|
||||
int rv;
|
||||
int error;
|
||||
bool readonly;
|
||||
const Branch *branch;
|
||||
|
||||
for(size_t i = 0, ei = basepaths.size(); i != ei; i++)
|
||||
{
|
||||
basepath = &basepaths[i];
|
||||
error = ENOENT;
|
||||
for(size_t i = 0, ei = branches_.size(); i != ei; i++)
|
||||
{
|
||||
branch = &branches_[i];
|
||||
|
||||
if(!fs::exists(*basepath,fusepath))
|
||||
continue;
|
||||
if(!fs::exists(branch->path,fusepath))
|
||||
error_and_continue(error,ENOENT);
|
||||
if(branch->ro())
|
||||
error_and_continue(error,EROFS);
|
||||
rv = fs::readonly(&branch->path,&readonly);
|
||||
if(rv == -1)
|
||||
error_and_continue(error,ENOENT);
|
||||
if(readonly)
|
||||
error_and_continue(error,EROFS);
|
||||
|
||||
paths.push_back(basepath);
|
||||
paths.push_back(&branch->path);
|
||||
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
return (errno=ENOENT,-1);
|
||||
}
|
||||
return (errno=error,-1);
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
_epff(const Category::Enum::Type type,
|
||||
const vector<string> &basepaths,
|
||||
const char *fusepath,
|
||||
const uint64_t minfreespace,
|
||||
vector<const string*> &paths)
|
||||
{
|
||||
if(type == Category::Enum::create)
|
||||
return _epff_create(basepaths,fusepath,minfreespace,paths);
|
||||
static
|
||||
int
|
||||
search(const Branches &branches_,
|
||||
const char *fusepath,
|
||||
vector<const string*> &paths)
|
||||
{
|
||||
const Branch *branch;
|
||||
|
||||
return _epff_other(basepaths,fusepath,paths);
|
||||
for(size_t i = 0, ei = branches_.size(); i != ei; i++)
|
||||
{
|
||||
branch = &branches_[i];
|
||||
|
||||
if(!fs::exists(branch->path,fusepath))
|
||||
continue;
|
||||
|
||||
paths.push_back(&branch->path);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return (errno=ENOENT,-1);
|
||||
}
|
||||
}
|
||||
|
||||
namespace mergerfs
|
||||
{
|
||||
int
|
||||
Policy::Func::epff(const Category::Enum::Type type,
|
||||
const vector<string> &basepaths,
|
||||
const Branches &branches_,
|
||||
const char *fusepath,
|
||||
const uint64_t minfreespace,
|
||||
vector<const string*> &paths)
|
||||
{
|
||||
int rv;
|
||||
|
||||
rv = _epff(type,basepaths,fusepath,minfreespace,paths);
|
||||
if(rv == -1)
|
||||
rv = Policy::Func::ff(type,basepaths,fusepath,minfreespace,paths);
|
||||
|
||||
return rv;
|
||||
switch(type)
|
||||
{
|
||||
case Category::Enum::create:
|
||||
return epff::create(branches_,fusepath,minfreespace,paths);
|
||||
case Category::Enum::action:
|
||||
return epff::action(branches_,fusepath,paths);
|
||||
case Category::Enum::search:
|
||||
default:
|
||||
return epff::search(branches_,fusepath,paths);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include "fs_info.hpp"
|
||||
#include "fs_path.hpp"
|
||||
#include "policy.hpp"
|
||||
#include "policy_error.hpp"
|
||||
|
||||
#include <limits>
|
||||
#include <string>
|
||||
|
@ -29,114 +30,156 @@ using std::string;
|
|||
using std::vector;
|
||||
using mergerfs::Category;
|
||||
|
||||
static
|
||||
int
|
||||
_eplfs_create(const vector<string> &basepaths,
|
||||
const char *fusepath,
|
||||
const uint64_t minfreespace,
|
||||
vector<const string*> &paths)
|
||||
namespace eplfs
|
||||
{
|
||||
int rv;
|
||||
uint64_t eplfs;
|
||||
fs::info_t info;
|
||||
const string *basepath;
|
||||
const string *eplfsbasepath;
|
||||
static
|
||||
int
|
||||
create(const Branches &branches_,
|
||||
const char *fusepath,
|
||||
const uint64_t minfreespace,
|
||||
vector<const string*> &paths)
|
||||
{
|
||||
int rv;
|
||||
int error;
|
||||
uint64_t eplfs;
|
||||
fs::info_t info;
|
||||
const Branch *branch;
|
||||
const string *eplfsbasepath;
|
||||
|
||||
eplfs = std::numeric_limits<uint64_t>::max();
|
||||
eplfsbasepath = NULL;
|
||||
for(size_t i = 0, ei = basepaths.size(); i != ei; i++)
|
||||
{
|
||||
basepath = &basepaths[i];
|
||||
error = ENOENT;
|
||||
eplfs = std::numeric_limits<uint64_t>::max();
|
||||
eplfsbasepath = NULL;
|
||||
for(size_t i = 0, ei = branches_.size(); i != ei; i++)
|
||||
{
|
||||
branch = &branches_[i];
|
||||
|
||||
rv = fs::info(basepath,fusepath,&info);
|
||||
if(rv == -1)
|
||||
continue;
|
||||
if(info.readonly)
|
||||
continue;
|
||||
if(info.spaceavail < minfreespace)
|
||||
continue;
|
||||
if(info.spaceavail > eplfs)
|
||||
continue;
|
||||
if(!fs::exists(branch->path,fusepath))
|
||||
error_and_continue(error,ENOENT);
|
||||
if(branch->ro_or_nw())
|
||||
error_and_continue(error,EROFS);
|
||||
rv = fs::info(&branch->path,&info);
|
||||
if(rv == -1)
|
||||
error_and_continue(error,ENOENT);
|
||||
if(info.readonly)
|
||||
error_and_continue(error,EROFS);
|
||||
if(info.spaceavail < minfreespace)
|
||||
error_and_continue(error,ENOSPC);
|
||||
if(info.spaceavail > eplfs)
|
||||
continue;
|
||||
|
||||
eplfs = info.spaceavail;
|
||||
eplfsbasepath = basepath;
|
||||
}
|
||||
eplfs = info.spaceavail;
|
||||
eplfsbasepath = &branch->path;
|
||||
}
|
||||
|
||||
if(eplfsbasepath == NULL)
|
||||
return (errno=ENOENT,-1);
|
||||
if(eplfsbasepath == NULL)
|
||||
return (errno=error,-1);
|
||||
|
||||
paths.push_back(eplfsbasepath);
|
||||
paths.push_back(eplfsbasepath);
|
||||
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
_eplfs_other(const vector<string> &basepaths,
|
||||
const char *fusepath,
|
||||
vector<const string*> &paths)
|
||||
{
|
||||
int rv;
|
||||
uint64_t eplfs;
|
||||
uint64_t spaceavail;
|
||||
const string *basepath;
|
||||
const string *eplfsbasepath;
|
||||
static
|
||||
int
|
||||
action(const Branches &branches_,
|
||||
const char *fusepath,
|
||||
vector<const string*> &paths)
|
||||
{
|
||||
int rv;
|
||||
int error;
|
||||
uint64_t eplfs;
|
||||
fs::info_t info;
|
||||
const Branch *branch;
|
||||
const string *eplfsbasepath;
|
||||
|
||||
eplfs = std::numeric_limits<uint64_t>::max();
|
||||
eplfsbasepath = NULL;
|
||||
for(size_t i = 0, ei = basepaths.size(); i != ei; i++)
|
||||
{
|
||||
basepath = &basepaths[i];
|
||||
error = ENOENT;
|
||||
eplfs = std::numeric_limits<uint64_t>::max();
|
||||
eplfsbasepath = NULL;
|
||||
for(size_t i = 0, ei = branches_.size(); i != ei; i++)
|
||||
{
|
||||
branch = &branches_[i];
|
||||
|
||||
if(!fs::exists(*basepath,fusepath))
|
||||
continue;
|
||||
rv = fs::spaceavail(basepath,&spaceavail);
|
||||
if(rv == -1)
|
||||
continue;
|
||||
if(spaceavail > eplfs)
|
||||
continue;
|
||||
if(!fs::exists(branch->path,fusepath))
|
||||
error_and_continue(error,ENOENT);
|
||||
if(branch->ro())
|
||||
error_and_continue(error,EROFS);
|
||||
rv = fs::info(&branch->path,&info);
|
||||
if(rv == -1)
|
||||
error_and_continue(error,ENOENT);
|
||||
if(info.readonly)
|
||||
error_and_continue(error,EROFS);
|
||||
if(info.spaceavail > eplfs)
|
||||
continue;
|
||||
|
||||
eplfs = spaceavail;
|
||||
eplfsbasepath = basepath;
|
||||
}
|
||||
eplfs = info.spaceavail;
|
||||
eplfsbasepath = &branch->path;
|
||||
}
|
||||
|
||||
if(eplfsbasepath == NULL)
|
||||
return (errno=ENOENT,-1);
|
||||
if(eplfsbasepath == NULL)
|
||||
return (errno=error,-1);
|
||||
|
||||
paths.push_back(eplfsbasepath);
|
||||
paths.push_back(eplfsbasepath);
|
||||
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
_eplfs(const Category::Enum::Type type,
|
||||
const vector<string> &basepaths,
|
||||
const char *fusepath,
|
||||
const uint64_t minfreespace,
|
||||
vector<const string*> &paths)
|
||||
{
|
||||
if(type == Category::Enum::create)
|
||||
return _eplfs_create(basepaths,fusepath,minfreespace,paths);
|
||||
static
|
||||
int
|
||||
search(const Branches &branches_,
|
||||
const char *fusepath,
|
||||
vector<const string*> &paths)
|
||||
{
|
||||
int rv;
|
||||
uint64_t eplfs;
|
||||
uint64_t spaceavail;
|
||||
const Branch *branch;
|
||||
const string *eplfsbasepath;
|
||||
|
||||
return _eplfs_other(basepaths,fusepath,paths);
|
||||
eplfs = std::numeric_limits<uint64_t>::max();
|
||||
eplfsbasepath = NULL;
|
||||
for(size_t i = 0, ei = branches_.size(); i != ei; i++)
|
||||
{
|
||||
branch = &branches_[i];
|
||||
|
||||
if(!fs::exists(branch->path,fusepath))
|
||||
continue;
|
||||
rv = fs::spaceavail(&branch->path,&spaceavail);
|
||||
if(rv == -1)
|
||||
continue;
|
||||
if(spaceavail > eplfs)
|
||||
continue;
|
||||
|
||||
eplfs = spaceavail;
|
||||
eplfsbasepath = &branch->path;
|
||||
}
|
||||
|
||||
if(eplfsbasepath == NULL)
|
||||
return (errno=ENOENT,-1);
|
||||
|
||||
paths.push_back(eplfsbasepath);
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
namespace mergerfs
|
||||
{
|
||||
int
|
||||
Policy::Func::eplfs(const Category::Enum::Type type,
|
||||
const vector<string> &basepaths,
|
||||
const Branches &branches_,
|
||||
const char *fusepath,
|
||||
const uint64_t minfreespace,
|
||||
vector<const string*> &paths)
|
||||
{
|
||||
int rv;
|
||||
|
||||
rv = _eplfs(type,basepaths,fusepath,minfreespace,paths);
|
||||
if(rv == -1)
|
||||
rv = Policy::Func::lfs(type,basepaths,fusepath,minfreespace,paths);
|
||||
|
||||
return rv;
|
||||
switch(type)
|
||||
{
|
||||
case Category::Enum::create:
|
||||
return eplfs::create(branches_,fusepath,minfreespace,paths);
|
||||
case Category::Enum::action:
|
||||
return eplfs::action(branches_,fusepath,paths);
|
||||
case Category::Enum::search:
|
||||
default:
|
||||
return eplfs::search(branches_,fusepath,paths);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include "fs_info.hpp"
|
||||
#include "fs_path.hpp"
|
||||
#include "policy.hpp"
|
||||
#include "policy_error.hpp"
|
||||
|
||||
#include <limits>
|
||||
#include <string>
|
||||
|
@ -29,114 +30,156 @@ using std::string;
|
|||
using std::vector;
|
||||
using mergerfs::Category;
|
||||
|
||||
static
|
||||
int
|
||||
_eplus_create(const vector<string> &basepaths,
|
||||
const char *fusepath,
|
||||
const uint64_t minfreespace,
|
||||
vector<const string*> &paths)
|
||||
namespace eplus
|
||||
{
|
||||
int rv;
|
||||
uint64_t eplus;
|
||||
fs::info_t info;
|
||||
const string *basepath;
|
||||
const string *eplusbasepath;
|
||||
static
|
||||
int
|
||||
create(const Branches &branches_,
|
||||
const char *fusepath,
|
||||
const uint64_t minfreespace,
|
||||
vector<const string*> &paths)
|
||||
{
|
||||
int rv;
|
||||
int error;
|
||||
uint64_t eplus;
|
||||
fs::info_t info;
|
||||
const Branch *branch;
|
||||
const string *eplusbasepath;
|
||||
|
||||
eplus = std::numeric_limits<uint64_t>::max();
|
||||
eplusbasepath = NULL;
|
||||
for(size_t i = 0, ei = basepaths.size(); i != ei; i++)
|
||||
{
|
||||
basepath = &basepaths[i];
|
||||
error = ENOENT;
|
||||
eplus = std::numeric_limits<uint64_t>::max();
|
||||
eplusbasepath = NULL;
|
||||
for(size_t i = 0, ei = branches_.size(); i != ei; i++)
|
||||
{
|
||||
branch = &branches_[i];
|
||||
|
||||
rv = fs::info(basepath,fusepath,&info);
|
||||
if(rv == -1)
|
||||
continue;
|
||||
if(info.readonly)
|
||||
continue;
|
||||
if(info.spaceavail < minfreespace)
|
||||
continue;
|
||||
if(info.spaceused >= eplus)
|
||||
continue;
|
||||
if(!fs::exists(branch->path,fusepath))
|
||||
error_and_continue(error,ENOENT);
|
||||
if(branch->ro_or_nw())
|
||||
error_and_continue(error,EROFS);
|
||||
rv = fs::info(&branch->path,&info);
|
||||
if(rv == -1)
|
||||
error_and_continue(error,ENOENT);
|
||||
if(info.readonly)
|
||||
error_and_continue(error,EROFS);
|
||||
if(info.spaceavail < minfreespace)
|
||||
error_and_continue(error,ENOSPC);
|
||||
if(info.spaceused >= eplus)
|
||||
continue;
|
||||
|
||||
eplus = info.spaceused;
|
||||
eplusbasepath = basepath;
|
||||
}
|
||||
eplus = info.spaceused;
|
||||
eplusbasepath = &branch->path;
|
||||
}
|
||||
|
||||
if(eplusbasepath == NULL)
|
||||
return (errno=ENOENT,-1);
|
||||
if(eplusbasepath == NULL)
|
||||
return (errno=error,-1);
|
||||
|
||||
paths.push_back(eplusbasepath);
|
||||
paths.push_back(eplusbasepath);
|
||||
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
_eplus_other(const vector<string> &basepaths,
|
||||
const char *fusepath,
|
||||
vector<const string*> &paths)
|
||||
{
|
||||
int rv;
|
||||
uint64_t eplus;
|
||||
uint64_t spaceused;
|
||||
const string *basepath;
|
||||
const string *eplusbasepath;
|
||||
static
|
||||
int
|
||||
action(const Branches &branches_,
|
||||
const char *fusepath,
|
||||
vector<const string*> &paths)
|
||||
{
|
||||
int rv;
|
||||
int error;
|
||||
uint64_t eplus;
|
||||
fs::info_t info;
|
||||
const Branch *branch;
|
||||
const string *eplusbasepath;
|
||||
|
||||
eplus = 0;
|
||||
eplusbasepath = NULL;
|
||||
for(size_t i = 0, ei = basepaths.size(); i != ei; i++)
|
||||
{
|
||||
basepath = &basepaths[i];
|
||||
error = ENOENT;
|
||||
eplus = std::numeric_limits<uint64_t>::max();
|
||||
eplusbasepath = NULL;
|
||||
for(size_t i = 0, ei = branches_.size(); i != ei; i++)
|
||||
{
|
||||
branch = &branches_[i];
|
||||
|
||||
if(!fs::exists(*basepath,fusepath))
|
||||
continue;
|
||||
rv = fs::spaceused(basepath,&spaceused);
|
||||
if(rv == -1)
|
||||
continue;
|
||||
if(spaceused >= eplus)
|
||||
continue;
|
||||
if(!fs::exists(branch->path,fusepath))
|
||||
error_and_continue(error,ENOENT);
|
||||
if(branch->ro())
|
||||
error_and_continue(error,EROFS);
|
||||
rv = fs::info(&branch->path,&info);
|
||||
if(rv == -1)
|
||||
error_and_continue(error,ENOENT);
|
||||
if(info.readonly)
|
||||
error_and_continue(error,EROFS);
|
||||
if(info.spaceused >= eplus)
|
||||
continue;
|
||||
|
||||
eplus = spaceused;
|
||||
eplusbasepath = basepath;
|
||||
}
|
||||
eplus = info.spaceused;
|
||||
eplusbasepath = &branch->path;
|
||||
}
|
||||
|
||||
if(eplusbasepath == NULL)
|
||||
return (errno=ENOENT,-1);
|
||||
if(eplusbasepath == NULL)
|
||||
return (errno=error,-1);
|
||||
|
||||
paths.push_back(eplusbasepath);
|
||||
paths.push_back(eplusbasepath);
|
||||
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
_eplus(const Category::Enum::Type type,
|
||||
const vector<string> &basepaths,
|
||||
const char *fusepath,
|
||||
const uint64_t minfreespace,
|
||||
vector<const string*> &paths)
|
||||
{
|
||||
if(type == Category::Enum::create)
|
||||
return _eplus_create(basepaths,fusepath,minfreespace,paths);
|
||||
static
|
||||
int
|
||||
search(const Branches &branches_,
|
||||
const char *fusepath,
|
||||
vector<const string*> &paths)
|
||||
{
|
||||
int rv;
|
||||
uint64_t eplus;
|
||||
uint64_t spaceused;
|
||||
const Branch *branch;
|
||||
const string *eplusbasepath;
|
||||
|
||||
return _eplus_other(basepaths,fusepath,paths);
|
||||
eplus = 0;
|
||||
eplusbasepath = NULL;
|
||||
for(size_t i = 0, ei = branches_.size(); i != ei; i++)
|
||||
{
|
||||
branch = &branches_[i];
|
||||
|
||||
if(!fs::exists(branch->path,fusepath))
|
||||
continue;
|
||||
rv = fs::spaceused(&branch->path,&spaceused);
|
||||
if(rv == -1)
|
||||
continue;
|
||||
if(spaceused >= eplus)
|
||||
continue;
|
||||
|
||||
eplus = spaceused;
|
||||
eplusbasepath = &branch->path;
|
||||
}
|
||||
|
||||
if(eplusbasepath == NULL)
|
||||
return (errno=ENOENT,-1);
|
||||
|
||||
paths.push_back(eplusbasepath);
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
namespace mergerfs
|
||||
{
|
||||
int
|
||||
Policy::Func::eplus(const Category::Enum::Type type,
|
||||
const vector<string> &basepaths,
|
||||
const Branches &branches_,
|
||||
const char *fusepath,
|
||||
const uint64_t minfreespace,
|
||||
vector<const string*> &paths)
|
||||
{
|
||||
int rv;
|
||||
|
||||
rv = _eplus(type,basepaths,fusepath,minfreespace,paths);
|
||||
if(rv == -1)
|
||||
rv = Policy::Func::lus(type,basepaths,fusepath,minfreespace,paths);
|
||||
|
||||
return rv;
|
||||
switch(type)
|
||||
{
|
||||
case Category::Enum::create:
|
||||
return eplus::create(branches_,fusepath,minfreespace,paths);
|
||||
case Category::Enum::action:
|
||||
return eplus::action(branches_,fusepath,paths);
|
||||
case Category::Enum::search:
|
||||
default:
|
||||
return eplus::search(branches_,fusepath,paths);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include "fs_info.hpp"
|
||||
#include "fs_path.hpp"
|
||||
#include "policy.hpp"
|
||||
#include "policy_error.hpp"
|
||||
|
||||
#include <limits>
|
||||
#include <string>
|
||||
|
@ -29,114 +30,156 @@ using std::string;
|
|||
using std::vector;
|
||||
using mergerfs::Category;
|
||||
|
||||
static
|
||||
int
|
||||
_epmfs_create(const vector<string> &basepaths,
|
||||
const char *fusepath,
|
||||
const uint64_t minfreespace,
|
||||
vector<const string*> &paths)
|
||||
namespace epmfs
|
||||
{
|
||||
int rv;
|
||||
uint64_t epmfs;
|
||||
fs::info_t info;
|
||||
const string *basepath;
|
||||
const string *epmfsbasepath;
|
||||
static
|
||||
int
|
||||
create(const Branches &branches_,
|
||||
const char *fusepath,
|
||||
const uint64_t minfreespace,
|
||||
vector<const string*> &paths)
|
||||
{
|
||||
int rv;
|
||||
int error;
|
||||
uint64_t epmfs;
|
||||
fs::info_t info;
|
||||
const Branch *branch;
|
||||
const string *epmfsbasepath;
|
||||
|
||||
epmfs = std::numeric_limits<uint64_t>::min();
|
||||
epmfsbasepath = NULL;
|
||||
for(size_t i = 0, ei = basepaths.size(); i != ei; i++)
|
||||
{
|
||||
basepath = &basepaths[i];
|
||||
error = ENOENT;
|
||||
epmfs = std::numeric_limits<uint64_t>::min();
|
||||
epmfsbasepath = NULL;
|
||||
for(size_t i = 0, ei = branches_.size(); i != ei; i++)
|
||||
{
|
||||
branch = &branches_[i];
|
||||
|
||||
rv = fs::info(basepath,fusepath,&info);
|
||||
if(rv == -1)
|
||||
continue;
|
||||
if(info.readonly)
|
||||
continue;
|
||||
if(info.spaceavail < minfreespace)
|
||||
continue;
|
||||
if(info.spaceavail < epmfs)
|
||||
continue;
|
||||
if(!fs::exists(branch->path,fusepath))
|
||||
error_and_continue(error,ENOENT);
|
||||
if(branch->ro_or_nw())
|
||||
error_and_continue(error,EROFS);
|
||||
rv = fs::info(&branch->path,&info);
|
||||
if(rv == -1)
|
||||
error_and_continue(error,ENOENT);
|
||||
if(info.readonly)
|
||||
error_and_continue(error,EROFS);
|
||||
if(info.spaceavail < minfreespace)
|
||||
error_and_continue(error,ENOSPC);
|
||||
if(info.spaceavail < epmfs)
|
||||
continue;
|
||||
|
||||
epmfs = info.spaceavail;
|
||||
epmfsbasepath = basepath;
|
||||
}
|
||||
epmfs = info.spaceavail;
|
||||
epmfsbasepath = &branch->path;
|
||||
}
|
||||
|
||||
if(epmfsbasepath == NULL)
|
||||
return (errno=ENOENT,-1);
|
||||
if(epmfsbasepath == NULL)
|
||||
return (errno=error,-1);
|
||||
|
||||
paths.push_back(epmfsbasepath);
|
||||
paths.push_back(epmfsbasepath);
|
||||
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
_epmfs_other(const vector<string> &basepaths,
|
||||
const char *fusepath,
|
||||
vector<const string*> &paths)
|
||||
{
|
||||
int rv;
|
||||
uint64_t epmfs;
|
||||
uint64_t spaceavail;
|
||||
const string *basepath;
|
||||
const string *epmfsbasepath;
|
||||
static
|
||||
int
|
||||
action(const Branches &branches_,
|
||||
const char *fusepath,
|
||||
vector<const string*> &paths)
|
||||
{
|
||||
int rv;
|
||||
int error;
|
||||
uint64_t epmfs;
|
||||
fs::info_t info;
|
||||
const Branch *branch;
|
||||
const string *epmfsbasepath;
|
||||
|
||||
epmfs = 0;
|
||||
epmfsbasepath = NULL;
|
||||
for(size_t i = 0, ei = basepaths.size(); i != ei; i++)
|
||||
{
|
||||
basepath = &basepaths[i];
|
||||
error = ENOENT;
|
||||
epmfs = std::numeric_limits<uint64_t>::min();
|
||||
epmfsbasepath = NULL;
|
||||
for(size_t i = 0, ei = branches_.size(); i != ei; i++)
|
||||
{
|
||||
branch = &branches_[i];
|
||||
|
||||
if(!fs::exists(*basepath,fusepath))
|
||||
continue;
|
||||
rv = fs::spaceavail(basepath,&spaceavail);
|
||||
if(rv == -1)
|
||||
continue;
|
||||
if(spaceavail < epmfs)
|
||||
continue;
|
||||
if(!fs::exists(branch->path,fusepath))
|
||||
error_and_continue(error,ENOENT);
|
||||
if(branch->ro())
|
||||
error_and_continue(error,EROFS);
|
||||
rv = fs::info(&branch->path,&info);
|
||||
if(rv == -1)
|
||||
error_and_continue(error,ENOENT);
|
||||
if(info.readonly)
|
||||
error_and_continue(error,EROFS);
|
||||
if(info.spaceavail < epmfs)
|
||||
continue;
|
||||
|
||||
epmfs = spaceavail;
|
||||
epmfsbasepath = basepath;
|
||||
}
|
||||
epmfs = info.spaceavail;
|
||||
epmfsbasepath = &branch->path;
|
||||
}
|
||||
|
||||
if(epmfsbasepath == NULL)
|
||||
return (errno=ENOENT,-1);
|
||||
if(epmfsbasepath == NULL)
|
||||
return (errno=error,-1);
|
||||
|
||||
paths.push_back(epmfsbasepath);
|
||||
paths.push_back(epmfsbasepath);
|
||||
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
_epmfs(const Category::Enum::Type type,
|
||||
const vector<string> &basepaths,
|
||||
const char *fusepath,
|
||||
const uint64_t minfreespace,
|
||||
vector<const string*> &paths)
|
||||
{
|
||||
if(type == Category::Enum::create)
|
||||
return _epmfs_create(basepaths,fusepath,minfreespace,paths);
|
||||
static
|
||||
int
|
||||
search(const Branches &branches_,
|
||||
const char *fusepath,
|
||||
vector<const string*> &paths)
|
||||
{
|
||||
int rv;
|
||||
uint64_t epmfs;
|
||||
uint64_t spaceavail;
|
||||
const Branch *branch;
|
||||
const string *epmfsbasepath;
|
||||
|
||||
return _epmfs_other(basepaths,fusepath,paths);
|
||||
epmfs = 0;
|
||||
epmfsbasepath = NULL;
|
||||
for(size_t i = 0, ei = branches_.size(); i != ei; i++)
|
||||
{
|
||||
branch = &branches_[i];
|
||||
|
||||
if(!fs::exists(branch->path,fusepath))
|
||||
continue;
|
||||
rv = fs::spaceavail(&branch->path,&spaceavail);
|
||||
if(rv == -1)
|
||||
continue;
|
||||
if(spaceavail < epmfs)
|
||||
continue;
|
||||
|
||||
epmfs = spaceavail;
|
||||
epmfsbasepath = &branch->path;
|
||||
}
|
||||
|
||||
if(epmfsbasepath == NULL)
|
||||
return (errno=ENOENT,-1);
|
||||
|
||||
paths.push_back(epmfsbasepath);
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
namespace mergerfs
|
||||
{
|
||||
int
|
||||
Policy::Func::epmfs(const Category::Enum::Type type,
|
||||
const vector<string> &basepaths,
|
||||
const Branches &branches_,
|
||||
const char *fusepath,
|
||||
const uint64_t minfreespace,
|
||||
vector<const string*> &paths)
|
||||
{
|
||||
int rv;
|
||||
|
||||
rv = _epmfs(type,basepaths,fusepath,minfreespace,paths);
|
||||
if(rv == -1)
|
||||
rv = Policy::Func::mfs(type,basepaths,fusepath,minfreespace,paths);
|
||||
|
||||
return rv;
|
||||
switch(type)
|
||||
{
|
||||
case Category::Enum::create:
|
||||
return epmfs::create(branches_,fusepath,minfreespace,paths);
|
||||
case Category::Enum::action:
|
||||
return epmfs::action(branches_,fusepath,paths);
|
||||
case Category::Enum::search:
|
||||
default:
|
||||
return epmfs::search(branches_,fusepath,paths);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,14 +28,14 @@ namespace mergerfs
|
|||
{
|
||||
int
|
||||
Policy::Func::eprand(const Category::Enum::Type type,
|
||||
const vector<string> &basepaths,
|
||||
const Branches &branches_,
|
||||
const char *fusepath,
|
||||
const uint64_t minfreespace,
|
||||
vector<const string*> &paths)
|
||||
{
|
||||
int rv;
|
||||
|
||||
rv = Policy::Func::epall(type,basepaths,fusepath,minfreespace,paths);
|
||||
rv = Policy::Func::epall(type,branches_,fusepath,minfreespace,paths);
|
||||
if(rv == 0)
|
||||
std::random_shuffle(paths.begin(),paths.end());
|
||||
|
||||
|
|
|
@ -27,7 +27,7 @@ namespace mergerfs
|
|||
{
|
||||
int
|
||||
Policy::Func::erofs(const Category::Enum::Type type,
|
||||
const vector<string> &basepaths,
|
||||
const Branches &branches_,
|
||||
const char *fusepath,
|
||||
const uint64_t minfreespace,
|
||||
vector<const string*> &paths)
|
||||
|
|
51
src/policy_error.hpp
Normal file
51
src/policy_error.hpp
Normal file
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
ISC License
|
||||
|
||||
Copyright (c) 2018, Antonio SJ Musumeci <trapexit@spawn.link>
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#define error_and_continue(CUR,ERR) \
|
||||
{ \
|
||||
policy::calc_error(CUR,ERR); \
|
||||
continue; \
|
||||
}
|
||||
|
||||
namespace policy
|
||||
{
|
||||
static
|
||||
inline
|
||||
void
|
||||
calc_error(int &cur_,
|
||||
int err_)
|
||||
{
|
||||
switch(cur_)
|
||||
{
|
||||
default:
|
||||
case ENOENT:
|
||||
cur_ = err_;
|
||||
break;
|
||||
case ENOSPC:
|
||||
if(err_ != ENOENT)
|
||||
cur_ = err_;
|
||||
break;
|
||||
case EROFS:
|
||||
if((err_ != ENOENT) && (err_ != ENOSPC))
|
||||
cur_ = err_;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -20,6 +20,7 @@
|
|||
#include "fs_info.hpp"
|
||||
#include "fs_path.hpp"
|
||||
#include "policy.hpp"
|
||||
#include "policy_error.hpp"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
@ -27,80 +28,55 @@
|
|||
using std::string;
|
||||
using std::vector;
|
||||
|
||||
static
|
||||
int
|
||||
_ff_create(const vector<string> &basepaths,
|
||||
const uint64_t minfreespace,
|
||||
vector<const string*> &paths)
|
||||
namespace ff
|
||||
{
|
||||
int rv;
|
||||
fs::info_t info;
|
||||
const string *basepath;
|
||||
const string *fallback;
|
||||
static
|
||||
int
|
||||
create(const Branches &branches_,
|
||||
const uint64_t minfreespace,
|
||||
vector<const string*> &paths)
|
||||
{
|
||||
int rv;
|
||||
int error;
|
||||
fs::info_t info;
|
||||
const Branch *branch;
|
||||
|
||||
fallback = NULL;
|
||||
for(size_t i = 0, ei = basepaths.size(); i != ei; i++)
|
||||
{
|
||||
basepath = &basepaths[i];
|
||||
error = ENOENT;
|
||||
for(size_t i = 0, ei = branches_.size(); i != ei; i++)
|
||||
{
|
||||
branch = &branches_[i];
|
||||
|
||||
rv = fs::info(basepath,&info);
|
||||
if(rv == -1)
|
||||
continue;
|
||||
if(info.readonly)
|
||||
continue;
|
||||
if(fallback == NULL)
|
||||
fallback = basepath;
|
||||
if(info.spaceavail < minfreespace)
|
||||
continue;
|
||||
if(branch->ro_or_nw())
|
||||
error_and_continue(error,EROFS);
|
||||
rv = fs::info(&branch->path,&info);
|
||||
if(rv == -1)
|
||||
error_and_continue(error,ENOENT);
|
||||
if(info.readonly)
|
||||
error_and_continue(error,EROFS);
|
||||
if(info.spaceavail < minfreespace)
|
||||
error_and_continue(error,ENOSPC);
|
||||
|
||||
paths.push_back(basepath);
|
||||
paths.push_back(&branch->path);
|
||||
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(fallback == NULL)
|
||||
return (errno=ENOENT,-1);
|
||||
|
||||
paths.push_back(fallback);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
_ff_other(const vector<string> &basepaths,
|
||||
const char *fusepath,
|
||||
vector<const string*> &paths)
|
||||
{
|
||||
const string *basepath;
|
||||
|
||||
for(size_t i = 0, ei = basepaths.size(); i != ei; i++)
|
||||
{
|
||||
basepath = &basepaths[i];
|
||||
|
||||
if(!fs::exists(*basepath,fusepath))
|
||||
continue;
|
||||
|
||||
paths.push_back(basepath);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return (errno=ENOENT,-1);
|
||||
return (errno=error,-1);
|
||||
}
|
||||
}
|
||||
|
||||
namespace mergerfs
|
||||
{
|
||||
int
|
||||
Policy::Func::ff(const Category::Enum::Type type,
|
||||
const vector<string> &basepaths,
|
||||
const Branches &branches_,
|
||||
const char *fusepath,
|
||||
const uint64_t minfreespace,
|
||||
vector<const string*> &paths)
|
||||
{
|
||||
if(type == Category::Enum::create)
|
||||
return _ff_create(basepaths,minfreespace,paths);
|
||||
return ff::create(branches_,minfreespace,paths);
|
||||
|
||||
return _ff_other(basepaths,fusepath,paths);
|
||||
return Policy::Func::epff(type,branches_,fusepath,minfreespace,paths);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,7 +27,7 @@ namespace mergerfs
|
|||
{
|
||||
int
|
||||
Policy::Func::invalid(const Category::Enum::Type type,
|
||||
const vector<string> &basepaths,
|
||||
const Branches &branches_,
|
||||
const char *fusepath,
|
||||
const uint64_t minfreespace,
|
||||
vector<const string*> &paths)
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include "fs_info.hpp"
|
||||
#include "fs_path.hpp"
|
||||
#include "policy.hpp"
|
||||
#include "policy_error.hpp"
|
||||
|
||||
#include <limits>
|
||||
#include <string>
|
||||
|
@ -29,114 +30,65 @@ using std::string;
|
|||
using std::vector;
|
||||
using mergerfs::Category;
|
||||
|
||||
static
|
||||
int
|
||||
_lfs_create(const vector<string> &basepaths,
|
||||
const uint64_t minfreespace,
|
||||
vector<const string*> &paths)
|
||||
namespace lfs
|
||||
{
|
||||
int rv;
|
||||
uint64_t lfs;
|
||||
fs::info_t info;
|
||||
const string *basepath;
|
||||
const string *lfsbasepath;
|
||||
static
|
||||
int
|
||||
create(const Branches &branches_,
|
||||
const uint64_t minfreespace,
|
||||
vector<const string*> &paths)
|
||||
{
|
||||
int rv;
|
||||
int error;
|
||||
uint64_t lfs;
|
||||
fs::info_t info;
|
||||
const Branch *branch;
|
||||
const string *lfsbasepath;
|
||||
|
||||
lfs = std::numeric_limits<uint64_t>::max();
|
||||
lfsbasepath = NULL;
|
||||
for(size_t i = 0, ei = basepaths.size(); i != ei; i++)
|
||||
{
|
||||
basepath = &basepaths[i];
|
||||
error = ENOENT;
|
||||
lfs = std::numeric_limits<uint64_t>::max();
|
||||
lfsbasepath = NULL;
|
||||
for(size_t i = 0, ei = branches_.size(); i != ei; i++)
|
||||
{
|
||||
branch = &branches_[i];
|
||||
|
||||
rv = fs::info(basepath,&info);
|
||||
if(rv == -1)
|
||||
continue;
|
||||
if(info.readonly)
|
||||
continue;
|
||||
if(info.spaceavail < minfreespace)
|
||||
continue;
|
||||
if(info.spaceavail > lfs)
|
||||
continue;
|
||||
if(branch->ro_or_nw())
|
||||
error_and_continue(error,EROFS);
|
||||
rv = fs::info(&branch->path,&info);
|
||||
if(rv == -1)
|
||||
error_and_continue(error,ENOENT);
|
||||
if(info.readonly)
|
||||
error_and_continue(error,EROFS);
|
||||
if(info.spaceavail < minfreespace)
|
||||
error_and_continue(error,ENOSPC);
|
||||
if(info.spaceavail > lfs)
|
||||
continue;
|
||||
|
||||
lfs = info.spaceavail;
|
||||
lfsbasepath = basepath;
|
||||
}
|
||||
lfs = info.spaceavail;
|
||||
lfsbasepath = &branch->path;
|
||||
}
|
||||
|
||||
if(lfsbasepath == NULL)
|
||||
return (errno=ENOENT,-1);
|
||||
if(lfsbasepath == NULL)
|
||||
return (errno=error,-1);
|
||||
|
||||
paths.push_back(lfsbasepath);
|
||||
paths.push_back(lfsbasepath);
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
_lfs_other(const vector<string> &basepaths,
|
||||
const char *fusepath,
|
||||
vector<const string*> &paths)
|
||||
{
|
||||
int rv;
|
||||
uint64_t lfs;
|
||||
uint64_t spaceavail;
|
||||
const string *basepath;
|
||||
const string *lfsbasepath;
|
||||
|
||||
lfs = std::numeric_limits<uint64_t>::max();
|
||||
lfsbasepath = NULL;
|
||||
for(size_t i = 0, ei = basepaths.size(); i != ei; i++)
|
||||
{
|
||||
basepath = &basepaths[i];
|
||||
|
||||
if(!fs::exists(*basepath,fusepath))
|
||||
continue;
|
||||
rv = fs::spaceavail(basepath,&spaceavail);
|
||||
if(rv == -1)
|
||||
continue;
|
||||
if(spaceavail > lfs)
|
||||
continue;
|
||||
|
||||
lfs = spaceavail;
|
||||
lfsbasepath = basepath;
|
||||
}
|
||||
|
||||
if(lfsbasepath == NULL)
|
||||
return (errno=ENOENT,-1);
|
||||
|
||||
paths.push_back(lfsbasepath);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
_lfs(const Category::Enum::Type type,
|
||||
const vector<string> &basepaths,
|
||||
const char *fusepath,
|
||||
const uint64_t minfreespace,
|
||||
vector<const string*> &paths)
|
||||
{
|
||||
if(type == Category::Enum::create)
|
||||
return _lfs_create(basepaths,minfreespace,paths);
|
||||
|
||||
return _lfs_other(basepaths,fusepath,paths);
|
||||
}
|
||||
|
||||
|
||||
namespace mergerfs
|
||||
{
|
||||
int
|
||||
Policy::Func::lfs(const Category::Enum::Type type,
|
||||
const vector<string> &basepaths,
|
||||
const Branches &branches_,
|
||||
const char *fusepath,
|
||||
const uint64_t minfreespace,
|
||||
vector<const string*> &paths)
|
||||
{
|
||||
int rv;
|
||||
if(type == Category::Enum::create)
|
||||
return lfs::create(branches_,minfreespace,paths);
|
||||
|
||||
rv = _lfs(type,basepaths,fusepath,minfreespace,paths);
|
||||
if(rv == -1)
|
||||
rv = Policy::Func::mfs(type,basepaths,fusepath,minfreespace,paths);
|
||||
|
||||
return rv;
|
||||
return Policy::Func::eplfs(type,branches_,fusepath,minfreespace,paths);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include "fs_info.hpp"
|
||||
#include "fs_path.hpp"
|
||||
#include "policy.hpp"
|
||||
#include "policy_error.hpp"
|
||||
|
||||
#include <limits>
|
||||
#include <string>
|
||||
|
@ -29,113 +30,65 @@ using std::string;
|
|||
using std::vector;
|
||||
using mergerfs::Category;
|
||||
|
||||
static
|
||||
int
|
||||
_lus_create(const vector<string> &basepaths,
|
||||
const uint64_t minfreespace,
|
||||
vector<const string*> &paths)
|
||||
namespace lus
|
||||
{
|
||||
int rv;
|
||||
uint64_t lus;
|
||||
fs::info_t info;
|
||||
const string *basepath;
|
||||
const string *lusbasepath;
|
||||
static
|
||||
int
|
||||
create(const Branches &branches_,
|
||||
const uint64_t minfreespace,
|
||||
vector<const string*> &paths)
|
||||
{
|
||||
int rv;
|
||||
int error;
|
||||
uint64_t lus;
|
||||
fs::info_t info;
|
||||
const Branch *branch;
|
||||
const string *lusbasepath;
|
||||
|
||||
lus = std::numeric_limits<uint64_t>::max();
|
||||
lusbasepath = NULL;
|
||||
for(size_t i = 0, ei = basepaths.size(); i != ei; i++)
|
||||
{
|
||||
basepath = &basepaths[i];
|
||||
error = ENOENT;
|
||||
lus = std::numeric_limits<uint64_t>::max();
|
||||
lusbasepath = NULL;
|
||||
for(size_t i = 0, ei = branches_.size(); i != ei; i++)
|
||||
{
|
||||
branch = &branches_[i];
|
||||
|
||||
rv = fs::info(basepath,&info);
|
||||
if(rv == -1)
|
||||
continue;
|
||||
if(info.readonly)
|
||||
continue;
|
||||
if(info.spaceavail < minfreespace)
|
||||
continue;
|
||||
if(info.spaceused >= lus)
|
||||
continue;
|
||||
if(branch->ro_or_nw())
|
||||
error_and_continue(error,EROFS);
|
||||
rv = fs::info(&branch->path,&info);
|
||||
if(rv == -1)
|
||||
error_and_continue(error,ENOENT);
|
||||
if(info.readonly)
|
||||
error_and_continue(error,EROFS);
|
||||
if(info.spaceavail < minfreespace)
|
||||
error_and_continue(error,ENOSPC);
|
||||
if(info.spaceused >= lus)
|
||||
continue;
|
||||
|
||||
lus = info.spaceused;
|
||||
lusbasepath = basepath;
|
||||
}
|
||||
lus = info.spaceused;
|
||||
lusbasepath = &branch->path;
|
||||
}
|
||||
|
||||
if(lusbasepath == NULL)
|
||||
return (errno=ENOENT,-1);
|
||||
if(lusbasepath == NULL)
|
||||
return (errno=error,-1);
|
||||
|
||||
paths.push_back(lusbasepath);
|
||||
paths.push_back(lusbasepath);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
_lus_other(const vector<string> &basepaths,
|
||||
const char *fusepath,
|
||||
vector<const string*> &paths)
|
||||
{
|
||||
int rv;
|
||||
uint64_t lus;
|
||||
uint64_t spaceused;
|
||||
const string *basepath;
|
||||
const string *lusbasepath;
|
||||
|
||||
lus = 0;
|
||||
lusbasepath = NULL;
|
||||
for(size_t i = 0, ei = basepaths.size(); i != ei; i++)
|
||||
{
|
||||
basepath = &basepaths[i];
|
||||
|
||||
if(!fs::exists(*basepath,fusepath))
|
||||
continue;
|
||||
rv = fs::spaceused(basepath,&spaceused);
|
||||
if(rv == -1)
|
||||
continue;
|
||||
if(spaceused >= lus)
|
||||
continue;
|
||||
|
||||
lus = spaceused;
|
||||
lusbasepath = basepath;
|
||||
}
|
||||
|
||||
if(lusbasepath == NULL)
|
||||
return (errno=ENOENT,-1);
|
||||
|
||||
paths.push_back(lusbasepath);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
_lus(const Category::Enum::Type type,
|
||||
const vector<string> &basepaths,
|
||||
const char *fusepath,
|
||||
const uint64_t minfreespace,
|
||||
vector<const string*> &paths)
|
||||
{
|
||||
if(type == Category::Enum::create)
|
||||
return _lus_create(basepaths,minfreespace,paths);
|
||||
|
||||
return _lus_other(basepaths,fusepath,paths);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
namespace mergerfs
|
||||
{
|
||||
int
|
||||
Policy::Func::lus(const Category::Enum::Type type,
|
||||
const vector<string> &basepaths,
|
||||
const Branches &branches_,
|
||||
const char *fusepath,
|
||||
const uint64_t minfreespace,
|
||||
vector<const string*> &paths)
|
||||
{
|
||||
int rv;
|
||||
if(type == Category::Enum::create)
|
||||
return lus::create(branches_,minfreespace,paths);
|
||||
|
||||
rv = _lus(type,basepaths,fusepath,minfreespace,paths);
|
||||
if(rv == -1)
|
||||
rv = Policy::Func::mfs(type,basepaths,fusepath,minfreespace,paths);
|
||||
|
||||
return rv;
|
||||
return Policy::Func::eplus(type,branches_,fusepath,minfreespace,paths);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include "fs_info.hpp"
|
||||
#include "fs_path.hpp"
|
||||
#include "policy.hpp"
|
||||
#include "policy_error.hpp"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
@ -28,109 +29,65 @@ using std::string;
|
|||
using std::vector;
|
||||
using mergerfs::Category;
|
||||
|
||||
static
|
||||
int
|
||||
_mfs_create(const vector<string> &basepaths,
|
||||
vector<const string*> &paths)
|
||||
namespace mfs
|
||||
{
|
||||
int rv;
|
||||
uint64_t mfs;
|
||||
fs::info_t info;
|
||||
const string *basepath;
|
||||
const string *mfsbasepath;
|
||||
static
|
||||
int
|
||||
create(const Branches &branches_,
|
||||
const uint64_t minfreespace,
|
||||
vector<const string*> &paths)
|
||||
{
|
||||
int rv;
|
||||
int error;
|
||||
uint64_t mfs;
|
||||
fs::info_t info;
|
||||
const Branch *branch;
|
||||
const string *mfsbasepath;
|
||||
|
||||
mfs = 0;
|
||||
mfsbasepath = NULL;
|
||||
for(size_t i = 0, ei = basepaths.size(); i != ei; i++)
|
||||
{
|
||||
basepath = &basepaths[i];
|
||||
error = ENOENT;
|
||||
mfs = 0;
|
||||
mfsbasepath = NULL;
|
||||
for(size_t i = 0, ei = branches_.size(); i != ei; i++)
|
||||
{
|
||||
branch = &branches_[i];
|
||||
|
||||
rv = fs::info(basepath,&info);
|
||||
if(rv == -1)
|
||||
continue;
|
||||
if(info.readonly)
|
||||
continue;
|
||||
if(info.spaceavail < mfs)
|
||||
continue;
|
||||
if(branch->ro_or_nw())
|
||||
error_and_continue(error,EROFS);
|
||||
rv = fs::info(&branch->path,&info);
|
||||
if(rv == -1)
|
||||
error_and_continue(error,ENOENT);
|
||||
if(info.readonly)
|
||||
error_and_continue(error,EROFS);
|
||||
if(info.spaceavail < minfreespace)
|
||||
error_and_continue(error,ENOSPC);
|
||||
if(info.spaceavail < mfs)
|
||||
continue;
|
||||
|
||||
mfs = info.spaceavail;
|
||||
mfsbasepath = basepath;
|
||||
}
|
||||
mfs = info.spaceavail;
|
||||
mfsbasepath = &branch->path;
|
||||
}
|
||||
|
||||
if(mfsbasepath == NULL)
|
||||
return (errno=ENOENT,-1);
|
||||
if(mfsbasepath == NULL)
|
||||
return (errno=error,-1);
|
||||
|
||||
paths.push_back(mfsbasepath);
|
||||
paths.push_back(mfsbasepath);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
_mfs_other(const vector<string> &basepaths,
|
||||
const char *fusepath,
|
||||
vector<const string*> &paths)
|
||||
{
|
||||
int rv;
|
||||
uint64_t mfs;
|
||||
uint64_t spaceavail;
|
||||
const string *basepath;
|
||||
const string *mfsbasepath;
|
||||
|
||||
mfs = 0;
|
||||
mfsbasepath = NULL;
|
||||
for(size_t i = 0, ei = basepaths.size(); i != ei; i++)
|
||||
{
|
||||
basepath = &basepaths[i];
|
||||
|
||||
if(!fs::exists(*basepath,fusepath))
|
||||
continue;
|
||||
rv = fs::spaceavail(basepath,&spaceavail);
|
||||
if(rv == -1)
|
||||
continue;
|
||||
if(spaceavail < mfs)
|
||||
continue;
|
||||
|
||||
mfs = spaceavail;
|
||||
mfsbasepath = basepath;
|
||||
}
|
||||
|
||||
if(mfsbasepath == NULL)
|
||||
return (errno=ENOENT,-1);
|
||||
|
||||
paths.push_back(mfsbasepath);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
_mfs(const Category::Enum::Type type,
|
||||
const vector<string> &basepaths,
|
||||
const char *fusepath,
|
||||
vector<const string*> &paths)
|
||||
{
|
||||
if(type == Category::Enum::create)
|
||||
return _mfs_create(basepaths,paths);
|
||||
|
||||
return _mfs_other(basepaths,fusepath,paths);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
namespace mergerfs
|
||||
{
|
||||
int
|
||||
Policy::Func::mfs(const Category::Enum::Type type,
|
||||
const vector<string> &basepaths,
|
||||
const Branches &branches_,
|
||||
const char *fusepath,
|
||||
const uint64_t minfreespace,
|
||||
vector<const string*> &paths)
|
||||
{
|
||||
int rv;
|
||||
if(type == Category::Enum::create)
|
||||
return mfs::create(branches_,minfreespace,paths);
|
||||
|
||||
rv = _mfs(type,basepaths,fusepath,paths);
|
||||
if(rv == -1)
|
||||
rv = Policy::Func::ff(type,basepaths,fusepath,minfreespace,paths);
|
||||
|
||||
return rv;
|
||||
return Policy::Func::epmfs(type,branches_,fusepath,minfreespace,paths);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,12 +14,12 @@
|
|||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
|
||||
#include "errno.hpp"
|
||||
#include "fs.hpp"
|
||||
#include "fs_exists.hpp"
|
||||
#include "fs_path.hpp"
|
||||
#include "policy.hpp"
|
||||
#include "policy_error.hpp"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
@ -30,93 +30,151 @@
|
|||
using std::string;
|
||||
using std::vector;
|
||||
|
||||
static
|
||||
int
|
||||
_newest_create(const vector<string> &basepaths,
|
||||
const char *fusepath,
|
||||
vector<const string*> &paths)
|
||||
namespace newest
|
||||
{
|
||||
int rv;
|
||||
bool readonly;
|
||||
time_t newest;
|
||||
struct stat st;
|
||||
const string *basepath;
|
||||
const string *newestbasepath;
|
||||
static
|
||||
int
|
||||
create(const Branches &branches_,
|
||||
const char *fusepath,
|
||||
vector<const string*> &paths)
|
||||
{
|
||||
int rv;
|
||||
int error;
|
||||
bool readonly;
|
||||
time_t newest;
|
||||
struct stat st;
|
||||
const Branch *branch;
|
||||
const string *newestbasepath;
|
||||
|
||||
newest = std::numeric_limits<time_t>::min();
|
||||
newestbasepath = NULL;
|
||||
for(size_t i = 0, ei = basepaths.size(); i != ei; i++)
|
||||
{
|
||||
basepath = &basepaths[i];
|
||||
error = ENOENT;
|
||||
newest = std::numeric_limits<time_t>::min();
|
||||
newestbasepath = NULL;
|
||||
for(size_t i = 0, ei = branches_.size(); i != ei; i++)
|
||||
{
|
||||
branch = &branches_[i];
|
||||
|
||||
if(!fs::exists(*basepath,fusepath,st))
|
||||
continue;
|
||||
if(st.st_mtime < newest)
|
||||
continue;
|
||||
rv = fs::readonly(basepath,&readonly);
|
||||
if(rv == -1)
|
||||
continue;
|
||||
if(readonly)
|
||||
continue;
|
||||
if(!fs::exists(branch->path,fusepath,st))
|
||||
error_and_continue(error,ENOENT);
|
||||
if(branch->ro_or_nw())
|
||||
error_and_continue(error,EROFS);
|
||||
if(st.st_mtime < newest)
|
||||
continue;
|
||||
rv = fs::readonly(&branch->path,&readonly);
|
||||
if(rv == -1)
|
||||
error_and_continue(error,ENOENT);
|
||||
if(readonly)
|
||||
error_and_continue(error,EROFS);
|
||||
|
||||
newest = st.st_mtime;
|
||||
newestbasepath = basepath;
|
||||
}
|
||||
newest = st.st_mtime;
|
||||
newestbasepath = &branch->path;
|
||||
}
|
||||
|
||||
if(newestbasepath == NULL)
|
||||
return (errno=ENOENT,-1);
|
||||
if(newestbasepath == NULL)
|
||||
return (errno=error,-1);
|
||||
|
||||
paths.push_back(newestbasepath);
|
||||
paths.push_back(newestbasepath);
|
||||
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
_newest_other(const vector<string> &basepaths,
|
||||
const char *fusepath,
|
||||
vector<const string*> &paths)
|
||||
{
|
||||
time_t newest;
|
||||
struct stat st;
|
||||
const string *basepath;
|
||||
const string *newestbasepath;
|
||||
static
|
||||
int
|
||||
action(const Branches &branches_,
|
||||
const char *fusepath,
|
||||
vector<const string*> &paths)
|
||||
{
|
||||
int rv;
|
||||
int error;
|
||||
bool readonly;
|
||||
time_t newest;
|
||||
struct stat st;
|
||||
const Branch *branch;
|
||||
const string *newestbasepath;
|
||||
|
||||
newest = std::numeric_limits<time_t>::min();
|
||||
newestbasepath = NULL;
|
||||
for(size_t i = 0, ei = basepaths.size(); i != ei; i++)
|
||||
{
|
||||
basepath = &basepaths[i];
|
||||
error = ENOENT;
|
||||
newest = std::numeric_limits<time_t>::min();
|
||||
newestbasepath = NULL;
|
||||
for(size_t i = 0, ei = branches_.size(); i != ei; i++)
|
||||
{
|
||||
branch = &branches_[i];
|
||||
|
||||
if(!fs::exists(*basepath,fusepath,st))
|
||||
continue;
|
||||
if(st.st_mtime < newest)
|
||||
continue;
|
||||
if(!fs::exists(branch->path,fusepath,st))
|
||||
error_and_continue(error,ENOENT);
|
||||
if(branch->ro())
|
||||
error_and_continue(error,EROFS);
|
||||
if(st.st_mtime < newest)
|
||||
continue;
|
||||
rv = fs::readonly(&branch->path,&readonly);
|
||||
if(rv == -1)
|
||||
error_and_continue(error,ENOENT);
|
||||
if(readonly)
|
||||
error_and_continue(error,EROFS);
|
||||
|
||||
newest = st.st_mtime;
|
||||
newestbasepath = basepath;
|
||||
}
|
||||
newest = st.st_mtime;
|
||||
newestbasepath = &branch->path;
|
||||
}
|
||||
|
||||
if(newestbasepath == NULL)
|
||||
return (errno=ENOENT,-1);
|
||||
if(newestbasepath == NULL)
|
||||
return (errno=error,-1);
|
||||
|
||||
paths.push_back(newestbasepath);
|
||||
paths.push_back(newestbasepath);
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
search(const Branches &branches_,
|
||||
const char *fusepath,
|
||||
vector<const string*> &paths)
|
||||
{
|
||||
time_t newest;
|
||||
struct stat st;
|
||||
const Branch *branch;
|
||||
const string *newestbasepath;
|
||||
|
||||
newest = std::numeric_limits<time_t>::min();
|
||||
newestbasepath = NULL;
|
||||
for(size_t i = 0, ei = branches_.size(); i != ei; i++)
|
||||
{
|
||||
branch = &branches_[i];
|
||||
|
||||
if(!fs::exists(branch->path,fusepath,st))
|
||||
continue;
|
||||
if(st.st_mtime < newest)
|
||||
continue;
|
||||
|
||||
newest = st.st_mtime;
|
||||
newestbasepath = &branch->path;
|
||||
}
|
||||
|
||||
if(newestbasepath == NULL)
|
||||
return (errno=ENOENT,-1);
|
||||
|
||||
paths.push_back(newestbasepath);
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
namespace mergerfs
|
||||
{
|
||||
int
|
||||
Policy::Func::newest(const Category::Enum::Type type,
|
||||
const vector<string> &basepaths,
|
||||
const Branches &branches_,
|
||||
const char *fusepath,
|
||||
const uint64_t minfreespace,
|
||||
vector<const string*> &paths)
|
||||
{
|
||||
if(type == Category::Enum::create)
|
||||
return _newest_create(basepaths,fusepath,paths);
|
||||
|
||||
return _newest_other(basepaths,fusepath,paths);
|
||||
switch(type)
|
||||
{
|
||||
case Category::Enum::create:
|
||||
return newest::create(branches_,fusepath,paths);
|
||||
case Category::Enum::action:
|
||||
return newest::action(branches_,fusepath,paths);
|
||||
case Category::Enum::search:
|
||||
default:
|
||||
return newest::search(branches_,fusepath,paths);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,14 +28,14 @@ namespace mergerfs
|
|||
{
|
||||
int
|
||||
Policy::Func::rand(const Category::Enum::Type type,
|
||||
const vector<string> &basepaths,
|
||||
const Branches &branches_,
|
||||
const char *fusepath,
|
||||
const uint64_t minfreespace,
|
||||
vector<const string*> &paths)
|
||||
{
|
||||
int rv;
|
||||
|
||||
rv = Policy::Func::all(type,basepaths,fusepath,minfreespace,paths);
|
||||
rv = Policy::Func::all(type,branches_,fusepath,minfreespace,paths);
|
||||
if(rv == 0)
|
||||
std::random_shuffle(paths.begin(),paths.end());
|
||||
|
||||
|
|
|
@ -45,7 +45,7 @@ using std::vector;
|
|||
|
||||
static
|
||||
int
|
||||
_readdir(const vector<string> &srcmounts,
|
||||
_readdir(const Branches &branches_,
|
||||
const char *dirname,
|
||||
void *buf,
|
||||
const fuse_fill_dir_t filler)
|
||||
|
@ -54,13 +54,13 @@ _readdir(const vector<string> &srcmounts,
|
|||
string basepath;
|
||||
struct stat st = {0};
|
||||
|
||||
for(size_t i = 0, ei = srcmounts.size(); i != ei; i++)
|
||||
for(size_t i = 0, ei = branches_.size(); i != ei; i++)
|
||||
{
|
||||
int rv;
|
||||
int dirfd;
|
||||
DIR *dh;
|
||||
|
||||
fs::path::make(&srcmounts[i],dirname,basepath);
|
||||
basepath = fs::path::make(&branches_[i].path,dirname);
|
||||
|
||||
dh = fs::opendir(basepath);
|
||||
if(!dh)
|
||||
|
@ -109,9 +109,9 @@ namespace mergerfs
|
|||
const fuse_context *fc = fuse_get_context();
|
||||
const Config &config = Config::get(fc);
|
||||
const ugid::Set ugid(fc->uid,fc->gid);
|
||||
const rwlock::ReadGuard readlock(&config.srcmountslock);
|
||||
const rwlock::ReadGuard readlock(&config.branches_lock);
|
||||
|
||||
return ::_readdir(config.srcmounts,
|
||||
return ::_readdir(config.branches,
|
||||
di->fusepath.c_str(),
|
||||
buf,
|
||||
filler);
|
||||
|
|
|
@ -93,7 +93,7 @@ _readlink_core(const string *basepath,
|
|||
static
|
||||
int
|
||||
_readlink(Policy::Func::Search searchFunc,
|
||||
const vector<string> &srcmounts,
|
||||
const Branches &branches_,
|
||||
const uint64_t minfreespace,
|
||||
const char *fusepath,
|
||||
char *buf,
|
||||
|
@ -104,7 +104,7 @@ _readlink(Policy::Func::Search searchFunc,
|
|||
int rv;
|
||||
vector<const string*> basepaths;
|
||||
|
||||
rv = searchFunc(srcmounts,fusepath,minfreespace,basepaths);
|
||||
rv = searchFunc(branches_,fusepath,minfreespace,basepaths);
|
||||
if(rv == -1)
|
||||
return -errno;
|
||||
|
||||
|
@ -124,10 +124,10 @@ namespace mergerfs
|
|||
const fuse_context *fc = fuse_get_context();
|
||||
const Config &config = Config::get(fc);
|
||||
const ugid::Set ugid(fc->uid,fc->gid);
|
||||
const rwlock::ReadGuard readlock(&config.srcmountslock);
|
||||
const rwlock::ReadGuard readlock(&config.branches_lock);
|
||||
|
||||
return _readlink(config.readlink,
|
||||
config.srcmounts,
|
||||
config.branches,
|
||||
config.minfreespace,
|
||||
fusepath,
|
||||
buf,
|
||||
|
|
|
@ -69,7 +69,7 @@ _removexattr_loop(const vector<const string*> &basepaths,
|
|||
static
|
||||
int
|
||||
_removexattr(Policy::Func::Action actionFunc,
|
||||
const vector<string> &srcmounts,
|
||||
const Branches &branches_,
|
||||
const uint64_t minfreespace,
|
||||
const char *fusepath,
|
||||
const char *attrname)
|
||||
|
@ -77,7 +77,7 @@ _removexattr(Policy::Func::Action actionFunc,
|
|||
int rv;
|
||||
vector<const string*> basepaths;
|
||||
|
||||
rv = actionFunc(srcmounts,fusepath,minfreespace,basepaths);
|
||||
rv = actionFunc(branches_,fusepath,minfreespace,basepaths);
|
||||
if(rv == -1)
|
||||
return -errno;
|
||||
|
||||
|
@ -101,10 +101,10 @@ namespace mergerfs
|
|||
return -config.xattr;
|
||||
|
||||
const ugid::Set ugid(fc->uid,fc->gid);
|
||||
const rwlock::ReadGuard readlock(&config.srcmountslock);
|
||||
const rwlock::ReadGuard readlock(&config.branches_lock);
|
||||
|
||||
return _removexattr(config.removexattr,
|
||||
config.srcmounts,
|
||||
config.branches,
|
||||
config.minfreespace,
|
||||
fusepath,
|
||||
attrname);
|
||||
|
|
|
@ -100,7 +100,7 @@ static
|
|||
int
|
||||
_rename_create_path(Policy::Func::Search searchFunc,
|
||||
Policy::Func::Action actionFunc,
|
||||
const vector<string> &srcmounts,
|
||||
const Branches &branches_,
|
||||
const uint64_t minfreespace,
|
||||
const char *oldfusepath,
|
||||
const char *newfusepath)
|
||||
|
@ -112,20 +112,20 @@ _rename_create_path(Policy::Func::Search searchFunc,
|
|||
vector<const string*> newbasepath;
|
||||
vector<const string*> oldbasepaths;
|
||||
|
||||
rv = actionFunc(srcmounts,oldfusepath,minfreespace,oldbasepaths);
|
||||
rv = actionFunc(branches_,oldfusepath,minfreespace,oldbasepaths);
|
||||
if(rv == -1)
|
||||
return -errno;
|
||||
|
||||
newfusedirpath = fs::path::dirname(newfusepath);
|
||||
|
||||
rv = searchFunc(srcmounts,newfusedirpath,minfreespace,newbasepath);
|
||||
rv = searchFunc(branches_,newfusedirpath,minfreespace,newbasepath);
|
||||
if(rv == -1)
|
||||
return -errno;
|
||||
|
||||
error = -1;
|
||||
for(size_t i = 0, ei = srcmounts.size(); i != ei; i++)
|
||||
for(size_t i = 0, ei = branches_.size(); i != ei; i++)
|
||||
{
|
||||
const string &oldbasepath = srcmounts[i];
|
||||
const string &oldbasepath = branches_[i].path;
|
||||
|
||||
_rename_create_path_core(oldbasepaths,
|
||||
oldbasepath,*newbasepath[0],
|
||||
|
@ -144,7 +144,7 @@ _rename_create_path(Policy::Func::Search searchFunc,
|
|||
static
|
||||
int
|
||||
_clonepath(Policy::Func::Search searchFunc,
|
||||
const vector<string> &srcmounts,
|
||||
const Branches &branches_,
|
||||
const uint64_t minfreespace,
|
||||
const string &dstbasepath,
|
||||
const string &fusedirpath)
|
||||
|
@ -152,7 +152,7 @@ _clonepath(Policy::Func::Search searchFunc,
|
|||
int rv;
|
||||
vector<const string*> srcbasepath;
|
||||
|
||||
rv = searchFunc(srcmounts,fusedirpath,minfreespace,srcbasepath);
|
||||
rv = searchFunc(branches_,fusedirpath,minfreespace,srcbasepath);
|
||||
if(rv == -1)
|
||||
return -errno;
|
||||
|
||||
|
@ -165,7 +165,7 @@ static
|
|||
int
|
||||
_clonepath_if_would_create(Policy::Func::Search searchFunc,
|
||||
Policy::Func::Create createFunc,
|
||||
const vector<string> &srcmounts,
|
||||
const Branches &branches_,
|
||||
const uint64_t minfreespace,
|
||||
const string &oldbasepath,
|
||||
const char *oldfusepath,
|
||||
|
@ -177,12 +177,12 @@ _clonepath_if_would_create(Policy::Func::Search searchFunc,
|
|||
|
||||
newfusedirpath = fs::path::dirname(newfusepath);
|
||||
|
||||
rv = createFunc(srcmounts,newfusedirpath,minfreespace,newbasepath);
|
||||
rv = createFunc(branches_,newfusedirpath,minfreespace,newbasepath);
|
||||
if(rv == -1)
|
||||
return rv;
|
||||
|
||||
if(oldbasepath == *newbasepath[0])
|
||||
return _clonepath(searchFunc,srcmounts,minfreespace,oldbasepath,newfusedirpath);
|
||||
return _clonepath(searchFunc,branches_,minfreespace,oldbasepath,newfusedirpath);
|
||||
|
||||
return (errno=EXDEV,-1);
|
||||
}
|
||||
|
@ -191,7 +191,7 @@ static
|
|||
void
|
||||
_rename_preserve_path_core(Policy::Func::Search searchFunc,
|
||||
Policy::Func::Create createFunc,
|
||||
const vector<string> &srcmounts,
|
||||
const Branches &branches_,
|
||||
const uint64_t minfreespace,
|
||||
const vector<const string*> &oldbasepaths,
|
||||
const string &oldbasepath,
|
||||
|
@ -217,7 +217,7 @@ _rename_preserve_path_core(Policy::Func::Search searchFunc,
|
|||
if((rv == -1) && (errno == ENOENT))
|
||||
{
|
||||
rv = _clonepath_if_would_create(searchFunc,createFunc,
|
||||
srcmounts,minfreespace,
|
||||
branches_,minfreespace,
|
||||
oldbasepath,oldfusepath,newfusepath);
|
||||
if(rv == 0)
|
||||
rv = fs::rename(oldfullpath,newfullpath);
|
||||
|
@ -238,7 +238,7 @@ int
|
|||
_rename_preserve_path(Policy::Func::Search searchFunc,
|
||||
Policy::Func::Action actionFunc,
|
||||
Policy::Func::Create createFunc,
|
||||
const vector<string> &srcmounts,
|
||||
const Branches &branches_,
|
||||
const uint64_t minfreespace,
|
||||
const char *oldfusepath,
|
||||
const char *newfusepath)
|
||||
|
@ -248,17 +248,17 @@ _rename_preserve_path(Policy::Func::Search searchFunc,
|
|||
vector<string> toremove;
|
||||
vector<const string*> oldbasepaths;
|
||||
|
||||
rv = actionFunc(srcmounts,oldfusepath,minfreespace,oldbasepaths);
|
||||
rv = actionFunc(branches_,oldfusepath,minfreespace,oldbasepaths);
|
||||
if(rv == -1)
|
||||
return -errno;
|
||||
|
||||
error = -1;
|
||||
for(size_t i = 0, ei = srcmounts.size(); i != ei; i++)
|
||||
for(size_t i = 0, ei = branches_.size(); i != ei; i++)
|
||||
{
|
||||
const string &oldbasepath = srcmounts[i];
|
||||
const string &oldbasepath = branches_[i].path;
|
||||
|
||||
_rename_preserve_path_core(searchFunc,createFunc,
|
||||
srcmounts,minfreespace,
|
||||
branches_,minfreespace,
|
||||
oldbasepaths,oldbasepath,
|
||||
oldfusepath,newfusepath,
|
||||
error,toremove);
|
||||
|
@ -281,20 +281,20 @@ namespace mergerfs
|
|||
const fuse_context *fc = fuse_get_context();
|
||||
const Config &config = Config::get(fc);
|
||||
const ugid::Set ugid(fc->uid,fc->gid);
|
||||
const rwlock::ReadGuard readlock(&config.srcmountslock);
|
||||
const rwlock::ReadGuard readlock(&config.branches_lock);
|
||||
|
||||
if(config.create->path_preserving() && !config.ignorepponrename)
|
||||
return _rename_preserve_path(config.getattr,
|
||||
config.rename,
|
||||
config.create,
|
||||
config.srcmounts,
|
||||
config.branches,
|
||||
config.minfreespace,
|
||||
oldpath,
|
||||
newpath);
|
||||
|
||||
return _rename_create_path(config.getattr,
|
||||
config.rename,
|
||||
config.srcmounts,
|
||||
config.branches,
|
||||
config.minfreespace,
|
||||
oldpath,
|
||||
newpath);
|
||||
|
|
|
@ -68,14 +68,14 @@ _rmdir_loop(const vector<const string*> &basepaths,
|
|||
static
|
||||
int
|
||||
_rmdir(Policy::Func::Action actionFunc,
|
||||
const vector<string> &srcmounts,
|
||||
const Branches &branches_,
|
||||
const uint64_t minfreespace,
|
||||
const char *fusepath)
|
||||
{
|
||||
int rv;
|
||||
vector<const string*> basepaths;
|
||||
|
||||
rv = actionFunc(srcmounts,fusepath,minfreespace,basepaths);
|
||||
rv = actionFunc(branches_,fusepath,minfreespace,basepaths);
|
||||
if(rv == -1)
|
||||
return -errno;
|
||||
|
||||
|
@ -92,10 +92,10 @@ namespace mergerfs
|
|||
const fuse_context *fc = fuse_get_context();
|
||||
const Config &config = Config::get(fc);
|
||||
const ugid::Set ugid(fc->uid,fc->gid);
|
||||
const rwlock::ReadGuard readguard(&config.srcmountslock);
|
||||
const rwlock::ReadGuard readguard(&config.branches_lock);
|
||||
|
||||
return _rmdir(config.rmdir,
|
||||
config.srcmounts,
|
||||
config.branches,
|
||||
config.minfreespace,
|
||||
fusepath);
|
||||
}
|
||||
|
|
117
src/setxattr.cpp
117
src/setxattr.cpp
|
@ -48,78 +48,6 @@ _is_attrname_security_capability(const char *attrname_)
|
|||
return (strcmp(attrname_,SECURITY_CAPABILITY) == 0);
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
_add_srcmounts(vector<string> &srcmounts,
|
||||
pthread_rwlock_t &srcmountslock,
|
||||
const string &destmount,
|
||||
const string &values,
|
||||
vector<string>::iterator pos)
|
||||
{
|
||||
vector<string> patterns;
|
||||
vector<string> additions;
|
||||
|
||||
str::split(patterns,values,':');
|
||||
fs::glob(patterns,additions);
|
||||
fs::realpathize(additions);
|
||||
|
||||
if(!additions.empty())
|
||||
{
|
||||
const rwlock::WriteGuard wrg(&srcmountslock);
|
||||
|
||||
srcmounts.insert(pos,
|
||||
additions.begin(),
|
||||
additions.end());
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
_erase_srcmounts(vector<string> &srcmounts,
|
||||
pthread_rwlock_t &srcmountslock,
|
||||
const string &values)
|
||||
{
|
||||
if(srcmounts.empty())
|
||||
return 0;
|
||||
|
||||
vector<string> patterns;
|
||||
|
||||
str::split(patterns,values,':');
|
||||
|
||||
{
|
||||
const rwlock::WriteGuard wrg(&srcmountslock);
|
||||
|
||||
str::erase_fnmatches(patterns,srcmounts);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
_replace_srcmounts(vector<string> &srcmounts,
|
||||
pthread_rwlock_t &srcmountslock,
|
||||
const string &destmount,
|
||||
const string &values)
|
||||
{
|
||||
vector<string> patterns;
|
||||
vector<string> newmounts;
|
||||
|
||||
str::split(patterns,values,':');
|
||||
fs::glob(patterns,newmounts);
|
||||
fs::realpathize(newmounts);
|
||||
|
||||
{
|
||||
const rwlock::WriteGuard wrg(&srcmountslock);
|
||||
|
||||
srcmounts.swap(newmounts);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
_split_attrval(const string &attrval,
|
||||
|
@ -138,10 +66,11 @@ static
|
|||
int
|
||||
_setxattr_srcmounts(const string &attrval,
|
||||
const int flags,
|
||||
vector<string> &srcmounts,
|
||||
pthread_rwlock_t &srcmountslock,
|
||||
const string &destmount)
|
||||
Branches &branches_,
|
||||
pthread_rwlock_t &branches_lock)
|
||||
{
|
||||
const rwlock::WriteGuard wrg(&branches_lock);
|
||||
|
||||
string instruction;
|
||||
string values;
|
||||
|
||||
|
@ -151,23 +80,25 @@ _setxattr_srcmounts(const string &attrval,
|
|||
_split_attrval(attrval,instruction,values);
|
||||
|
||||
if(instruction == "+")
|
||||
return _add_srcmounts(srcmounts,srcmountslock,destmount,values,srcmounts.end());
|
||||
branches_.add_end(values);
|
||||
else if(instruction == "+<")
|
||||
return _add_srcmounts(srcmounts,srcmountslock,destmount,values,srcmounts.begin());
|
||||
branches_.add_begin(values);
|
||||
else if(instruction == "+>")
|
||||
return _add_srcmounts(srcmounts,srcmountslock,destmount,values,srcmounts.end());
|
||||
branches_.add_end(values);
|
||||
else if(instruction == "-")
|
||||
return _erase_srcmounts(srcmounts,srcmountslock,values);
|
||||
branches_.erase_fnmatch(values);
|
||||
else if(instruction == "-<")
|
||||
return _erase_srcmounts(srcmounts,srcmountslock,srcmounts.front());
|
||||
branches_.erase_begin();
|
||||
else if(instruction == "->")
|
||||
return _erase_srcmounts(srcmounts,srcmountslock,srcmounts.back());
|
||||
branches_.erase_end();
|
||||
else if(instruction == "=")
|
||||
return _replace_srcmounts(srcmounts,srcmountslock,destmount,values);
|
||||
branches_.set(values);
|
||||
else if(instruction.empty())
|
||||
return _replace_srcmounts(srcmounts,srcmountslock,destmount,values);
|
||||
branches_.set(values);
|
||||
else
|
||||
return -EINVAL;
|
||||
|
||||
return -EINVAL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static
|
||||
|
@ -280,9 +211,13 @@ _setxattr_controlfile(Config &config,
|
|||
if(attr[2] == "srcmounts")
|
||||
return _setxattr_srcmounts(attrval,
|
||||
flags,
|
||||
config.srcmounts,
|
||||
config.srcmountslock,
|
||||
config.destmount);
|
||||
config.branches,
|
||||
config.branches_lock);
|
||||
else if(attr[2] == "branches")
|
||||
return _setxattr_srcmounts(attrval,
|
||||
flags,
|
||||
config.branches,
|
||||
config.branches_lock);
|
||||
else if(attr[2] == "minfreespace")
|
||||
return _setxattr_uint64_t(attrval,
|
||||
flags,
|
||||
|
@ -382,7 +317,7 @@ _setxattr_loop(const vector<const string*> &basepaths,
|
|||
static
|
||||
int
|
||||
_setxattr(Policy::Func::Action actionFunc,
|
||||
const vector<string> &srcmounts,
|
||||
const Branches &branches_,
|
||||
const uint64_t minfreespace,
|
||||
const char *fusepath,
|
||||
const char *attrname,
|
||||
|
@ -393,7 +328,7 @@ _setxattr(Policy::Func::Action actionFunc,
|
|||
int rv;
|
||||
vector<const string*> basepaths;
|
||||
|
||||
rv = actionFunc(srcmounts,fusepath,minfreespace,basepaths);
|
||||
rv = actionFunc(branches_,fusepath,minfreespace,basepaths);
|
||||
if(rv == -1)
|
||||
return -errno;
|
||||
|
||||
|
@ -428,10 +363,10 @@ namespace mergerfs
|
|||
return -config.xattr;
|
||||
|
||||
const ugid::Set ugid(fc->uid,fc->gid);
|
||||
const rwlock::ReadGuard readlock(&config.srcmountslock);
|
||||
const rwlock::ReadGuard readlock(&config.branches_lock);
|
||||
|
||||
return _setxattr(config.setxattr,
|
||||
config.srcmounts,
|
||||
config.branches,
|
||||
config.minfreespace,
|
||||
fusepath,
|
||||
attrname,
|
||||
|
|
|
@ -64,7 +64,7 @@ _merge_statvfs(struct statvfs * const out,
|
|||
|
||||
static
|
||||
void
|
||||
_statfs_core(const char *srcmount,
|
||||
_statfs_core(const string &path_,
|
||||
unsigned long &min_bsize,
|
||||
unsigned long &min_frsize,
|
||||
unsigned long &min_namemax,
|
||||
|
@ -74,11 +74,11 @@ _statfs_core(const char *srcmount,
|
|||
struct stat st;
|
||||
struct statvfs fsstat;
|
||||
|
||||
rv = fs::statvfs(srcmount,fsstat);
|
||||
rv = fs::statvfs(path_,fsstat);
|
||||
if(rv == -1)
|
||||
return;
|
||||
|
||||
rv = fs::stat(srcmount,st);
|
||||
rv = fs::stat(path_,st);
|
||||
if(rv == -1)
|
||||
return;
|
||||
|
||||
|
@ -94,17 +94,17 @@ _statfs_core(const char *srcmount,
|
|||
|
||||
static
|
||||
int
|
||||
_statfs(const vector<string> &srcmounts,
|
||||
struct statvfs &fsstat)
|
||||
_statfs(const Branches &branches_,
|
||||
struct statvfs &fsstat)
|
||||
{
|
||||
map<dev_t,struct statvfs> fsstats;
|
||||
unsigned long min_bsize = ULONG_MAX;
|
||||
unsigned long min_frsize = ULONG_MAX;
|
||||
unsigned long min_namemax = ULONG_MAX;
|
||||
|
||||
for(size_t i = 0, ei = srcmounts.size(); i < ei; i++)
|
||||
for(size_t i = 0, ei = branches_.size(); i < ei; i++)
|
||||
{
|
||||
_statfs_core(srcmounts[i].c_str(),min_bsize,min_frsize,min_namemax,fsstats);
|
||||
_statfs_core(branches_[i].path,min_bsize,min_frsize,min_namemax,fsstats);
|
||||
}
|
||||
|
||||
map<dev_t,struct statvfs>::iterator iter = fsstats.begin();
|
||||
|
@ -135,9 +135,9 @@ namespace mergerfs
|
|||
const fuse_context *fc = fuse_get_context();
|
||||
const Config &config = Config::get(fc);
|
||||
const ugid::Set ugid(fc->uid,fc->gid);
|
||||
const rwlock::ReadGuard readlock(&config.srcmountslock);
|
||||
const rwlock::ReadGuard readlock(&config.branches_lock);
|
||||
|
||||
return _statfs(config.srcmounts,
|
||||
return _statfs(config.branches,
|
||||
*stat);
|
||||
}
|
||||
}
|
||||
|
|
12
src/str.cpp
12
src/str.cpp
|
@ -147,4 +147,16 @@ namespace str
|
|||
return ((s0.size() >= s1.size()) &&
|
||||
(s0.compare(0,s1.size(),s1) == 0));
|
||||
}
|
||||
|
||||
bool
|
||||
ends_with(const string &str_,
|
||||
const string &suffix_)
|
||||
{
|
||||
if(suffix_.size() > str_.size())
|
||||
return false;
|
||||
|
||||
return std::equal(suffix_.rbegin(),
|
||||
suffix_.rend(),
|
||||
str_.rbegin());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -56,4 +56,8 @@ namespace str
|
|||
bool
|
||||
isprefix(const std::string &s0,
|
||||
const std::string &s1);
|
||||
|
||||
bool
|
||||
ends_with(const std::string &str_,
|
||||
const std::string &suffix_);
|
||||
}
|
||||
|
|
|
@ -82,7 +82,7 @@ static
|
|||
int
|
||||
_symlink(Policy::Func::Search searchFunc,
|
||||
Policy::Func::Create createFunc,
|
||||
const vector<string> &srcmounts,
|
||||
const Branches &branches_,
|
||||
const uint64_t minfreespace,
|
||||
const char *oldpath,
|
||||
const char *newpath)
|
||||
|
@ -94,11 +94,11 @@ _symlink(Policy::Func::Search searchFunc,
|
|||
|
||||
newdirpath = fs::path::dirname(newpath);
|
||||
|
||||
rv = searchFunc(srcmounts,newdirpath,minfreespace,existingpaths);
|
||||
rv = searchFunc(branches_,newdirpath,minfreespace,existingpaths);
|
||||
if(rv == -1)
|
||||
return -errno;
|
||||
|
||||
rv = createFunc(srcmounts,newdirpath,minfreespace,newbasepaths);
|
||||
rv = createFunc(branches_,newdirpath,minfreespace,newbasepaths);
|
||||
if(rv == -1)
|
||||
return -errno;
|
||||
|
||||
|
@ -117,11 +117,11 @@ namespace mergerfs
|
|||
const fuse_context *fc = fuse_get_context();
|
||||
const Config &config = Config::get(fc);
|
||||
const ugid::Set ugid(fc->uid,fc->gid);
|
||||
const rwlock::ReadGuard readlock(&config.srcmountslock);
|
||||
const rwlock::ReadGuard readlock(&config.branches_lock);
|
||||
|
||||
return _symlink(config.getattr,
|
||||
config.symlink,
|
||||
config.srcmounts,
|
||||
config.branches,
|
||||
config.minfreespace,
|
||||
oldpath,
|
||||
newpath);
|
||||
|
|
|
@ -71,7 +71,7 @@ _truncate_loop(const vector<const string*> &basepaths,
|
|||
static
|
||||
int
|
||||
_truncate(Policy::Func::Action actionFunc,
|
||||
const vector<string> &srcmounts,
|
||||
const Branches &branches_,
|
||||
const uint64_t minfreespace,
|
||||
const char *fusepath,
|
||||
const off_t size)
|
||||
|
@ -79,7 +79,7 @@ _truncate(Policy::Func::Action actionFunc,
|
|||
int rv;
|
||||
vector<const string*> basepaths;
|
||||
|
||||
rv = actionFunc(srcmounts,fusepath,minfreespace,basepaths);
|
||||
rv = actionFunc(branches_,fusepath,minfreespace,basepaths);
|
||||
if(rv == -1)
|
||||
return -errno;
|
||||
|
||||
|
@ -97,10 +97,10 @@ namespace mergerfs
|
|||
const fuse_context *fc = fuse_get_context();
|
||||
const Config &config = Config::get(fc);
|
||||
const ugid::Set ugid(fc->uid,fc->gid);
|
||||
const rwlock::ReadGuard readlock(&config.srcmountslock);
|
||||
const rwlock::ReadGuard readlock(&config.branches_lock);
|
||||
|
||||
return _truncate(config.truncate,
|
||||
config.srcmounts,
|
||||
config.branches,
|
||||
config.minfreespace,
|
||||
fusepath,
|
||||
size);
|
||||
|
|
|
@ -68,14 +68,14 @@ _unlink_loop(const vector<const string*> &basepaths,
|
|||
static
|
||||
int
|
||||
_unlink(Policy::Func::Action actionFunc,
|
||||
const vector<string> &srcmounts,
|
||||
const Branches &branches_,
|
||||
const uint64_t minfreespace,
|
||||
const char *fusepath)
|
||||
{
|
||||
int rv;
|
||||
vector<const string*> basepaths;
|
||||
|
||||
rv = actionFunc(srcmounts,fusepath,minfreespace,basepaths);
|
||||
rv = actionFunc(branches_,fusepath,minfreespace,basepaths);
|
||||
if(rv == -1)
|
||||
return -errno;
|
||||
|
||||
|
@ -92,10 +92,10 @@ namespace mergerfs
|
|||
const fuse_context *fc = fuse_get_context();
|
||||
const Config &config = Config::get(fc);
|
||||
const ugid::Set ugid(fc->uid,fc->gid);
|
||||
const rwlock::ReadGuard readlock(&config.srcmountslock);
|
||||
const rwlock::ReadGuard readlock(&config.branches_lock);
|
||||
|
||||
return _unlink(config.unlink,
|
||||
config.srcmounts,
|
||||
config.branches,
|
||||
config.minfreespace,
|
||||
fusepath);
|
||||
}
|
||||
|
|
|
@ -70,7 +70,7 @@ _utimens_loop(const vector<const string*> &basepaths,
|
|||
static
|
||||
int
|
||||
_utimens(Policy::Func::Action actionFunc,
|
||||
const vector<string> &srcmounts,
|
||||
const Branches &branches_,
|
||||
const uint64_t minfreespace,
|
||||
const char *fusepath,
|
||||
const timespec ts[2])
|
||||
|
@ -78,7 +78,7 @@ _utimens(Policy::Func::Action actionFunc,
|
|||
int rv;
|
||||
vector<const string*> basepaths;
|
||||
|
||||
rv = actionFunc(srcmounts,fusepath,minfreespace,basepaths);
|
||||
rv = actionFunc(branches_,fusepath,minfreespace,basepaths);
|
||||
if(rv == -1)
|
||||
return -errno;
|
||||
|
||||
|
@ -96,10 +96,10 @@ namespace mergerfs
|
|||
const fuse_context *fc = fuse_get_context();
|
||||
const Config &config = Config::get(fc);
|
||||
const ugid::Set ugid(fc->uid,fc->gid);
|
||||
const rwlock::ReadGuard readlock(&config.srcmountslock);
|
||||
const rwlock::ReadGuard readlock(&config.branches_lock);
|
||||
|
||||
return _utimens(config.utimens,
|
||||
config.srcmounts,
|
||||
config.branches,
|
||||
config.minfreespace,
|
||||
fusepath,
|
||||
ts);
|
||||
|
|
|
@ -14,8 +14,6 @@
|
|||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <fuse.h>
|
||||
|
||||
#include "config.hpp"
|
||||
#include "errno.hpp"
|
||||
#include "fileinfo.hpp"
|
||||
|
@ -24,7 +22,14 @@
|
|||
#include "rwlock.hpp"
|
||||
#include "ugid.hpp"
|
||||
|
||||
#include <fuse.h>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
using namespace mergerfs;
|
||||
using std::string;
|
||||
using std::vector;
|
||||
|
||||
typedef int (*WriteFunc)(const int,const void*,const size_t,const off_t);
|
||||
|
||||
|
@ -96,10 +101,13 @@ namespace mergerfs
|
|||
|
||||
if(config.moveonenospc)
|
||||
{
|
||||
const ugid::Set ugid(0,0);
|
||||
const rwlock::ReadGuard readlock(&config.srcmountslock);
|
||||
vector<string> paths;
|
||||
const ugid::Set ugid(0,0);
|
||||
const rwlock::ReadGuard readlock(&config.branches_lock);
|
||||
|
||||
rv = fs::movefile(config.srcmounts,fi->fusepath,count,fi->fd);
|
||||
config.branches.to_paths(paths);
|
||||
|
||||
rv = fs::movefile(paths,fi->fusepath,count,fi->fd);
|
||||
if(rv == -1)
|
||||
return -ENOSPC;
|
||||
|
||||
|
|
|
@ -14,14 +14,6 @@
|
|||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <fuse.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "config.hpp"
|
||||
#include "errno.hpp"
|
||||
#include "fileinfo.hpp"
|
||||
|
@ -31,6 +23,14 @@
|
|||
#include "ugid.hpp"
|
||||
#include "write.hpp"
|
||||
|
||||
#include <fuse.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
using std::string;
|
||||
using std::vector;
|
||||
using namespace mergerfs;
|
||||
|
@ -83,11 +83,14 @@ namespace mergerfs
|
|||
if(config.moveonenospc)
|
||||
{
|
||||
size_t extra;
|
||||
const ugid::Set ugid(0,0);
|
||||
const rwlock::ReadGuard readlock(&config.srcmountslock);
|
||||
vector<string> paths;
|
||||
const ugid::Set ugid(0,0);
|
||||
const rwlock::ReadGuard readlock(&config.branches_lock);
|
||||
|
||||
config.branches.to_paths(paths);
|
||||
|
||||
extra = fuse_buf_size(src);
|
||||
rv = fs::movefile(config.srcmounts,fi->fusepath,extra,fi->fd);
|
||||
rv = fs::movefile(paths,fi->fusepath,extra,fi->fd);
|
||||
if(rv == -1)
|
||||
return -ENOSPC;
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user