This commit is contained in:
Max
2016-11-06 18:24:25 +01:00
28 changed files with 6102 additions and 126 deletions
@@ -42,7 +42,7 @@ namespace Duplicati.Library.Localization
/// <summary>
/// Regular expression to match a locale
/// </summary>
public static readonly Regex CI_MATCHER = new Regex(@"[A-z]{2}(-[A-z]{4})?(-[A-z]{2})?");
public static readonly Regex CI_MATCHER = new Regex(@"[A-z]{2}([-_][A-z]{4})?([-_][A-z]{2})?");
/// <summary>
/// Returns a temporary disposable localization context
@@ -77,6 +77,7 @@ namespace Duplicati.Library.Localization
public static CultureInfo ParseCulture(string culture, bool returninvariant = false)
{
var ci = returninvariant ? CultureInfo.InvariantCulture : null;
culture = culture.Replace("_", "-");
if (CI_MATCHER.Match(culture).Success)
try { ci = new CultureInfo(culture); }
@@ -835,7 +835,7 @@ namespace Duplicati.Library.Main.Operation
if (m_options.StoreMetadata)
{
metadata = snapshot.GetMetadata(path);
metadata = snapshot.GetMetadata(path, attributes.HasFlag(System.IO.FileAttributes.ReparsePoint), m_symlinkPolicy == Options.SymlinkStrategy.Follow);
if (metadata == null)
metadata = new Dictionary<string, string>();
@@ -81,7 +81,9 @@ namespace Duplicati.Library.Snapshots
/// </summary>
/// <returns>The metadata for the given file or folder</returns>
/// <param name="file">The file or folder to examine</param>
Dictionary<string, string> GetMetadata(string file);
/// <param name="isSymlink">A flag indicating if the target is a symlink</param>
/// <param name="followSymlink">A flag indicating if a symlink should be followed</param>
Dictionary<string, string> GetMetadata(string file, bool isSymlink, bool followSymlink);
/// <summary>
/// Gets a value indicating if the path points to a block device
+1 -1
View File
@@ -57,7 +57,7 @@ namespace Duplicati.Library.Snapshots
IEnumerable<string> EnumerateFileSystemEntries(string path);
void SetMetadata(string path, Dictionary<string, string> metdata, bool restorePermissions);
Dictionary<string, string> GetMetadata(string path);
Dictionary<string, string> GetMetadata(string path, bool isSymlink, bool followSymlink);
}
}
+4 -2
View File
@@ -463,10 +463,12 @@ namespace Duplicati.Library.Snapshots
/// </summary>
/// <returns>The metadata for the given file or folder</returns>
/// <param name="file">The file or folder to examine</param>
public Dictionary<string, string> GetMetadata(string file)
/// <param name="isSymlink">A flag indicating if the target is a symlink</param>
/// <param name="followSymlink">A flag indicating if a symlink should be followed</param>
public Dictionary<string, string> GetMetadata(string file, bool isSymlink, bool followSymlink)
{
var local = ConvertToSnapshotPath(FindSnapShotByLocalPath(file), file);
return _sysIO.GetMetadata(local);
return _sysIO.GetMetadata(local, isSymlink, followSymlink);
}
/// <summary>
+4 -2
View File
@@ -176,7 +176,9 @@ namespace Duplicati.Library.Snapshots
/// </summary>
/// <returns>The metadata for the given file or folder</returns>
/// <param name="file">The file or folder to examine</param>
public abstract Dictionary<string, string> GetMetadata(string file);
/// <param name="isSymlink">A flag indicating if the target is a symlink</param>
/// <param name="followSymlink">A flag indicating if a symlink should be followed</param>
public abstract Dictionary<string, string> GetMetadata(string file, bool isSymlink, bool followSymlink);
/// <summary>
/// Gets a value indicating if the path points to a block device
@@ -189,7 +191,7 @@ namespace Duplicati.Library.Snapshots
/// Gets a unique hardlink target ID
/// </summary>
/// <returns>The hardlink ID</returns>
/// <param name="file">The file or folder to examine</param>
/// <param name="path">The file or folder to examine</param>
public abstract string HardlinkTargetID(string path);
#endregion
}
@@ -53,9 +53,11 @@ namespace Duplicati.Library.Snapshots
/// </summary>
/// <returns>The metadata for the given file or folder</returns>
/// <param name="file">The file or folder to examine</param>
public override Dictionary<string, string> GetMetadata(string file)
/// <param name="isSymlink">A flag indicating if the target is a symlink</param>
/// <param name="followSymlink">A flag indicating if a symlink should be followed</param>
public override Dictionary<string, string> GetMetadata(string file, bool isSymlink, bool followSymlink)
{
return _sysIO.GetMetadata(file);
return _sysIO.GetMetadata(file, isSymlink, followSymlink);
}
/// <summary>
@@ -146,9 +146,11 @@ namespace Duplicati.Library.Snapshots
/// </summary>
/// <returns>The metadata for the given file or folder</returns>
/// <param name="file">The file or folder to examine</param>
public override Dictionary<string, string> GetMetadata(string file)
/// <param name="isSymlink">A flag indicating if the target is a symlink</param>
/// <param name="followSymlink">A flag indicating if a symlink should be followed</param>
public override Dictionary<string, string> GetMetadata(string file, bool isSymlink, bool followSymlink)
{
return m_sysIO.GetMetadata(file);
return m_sysIO.GetMetadata(file, isSymlink, followSymlink);
}
/// <summary>
+2 -2
View File
@@ -165,12 +165,12 @@ namespace Duplicati.Library.Snapshots
Directory.Delete(NoSnapshot.NormalizePath(path), recursive);
}
public Dictionary<string, string> GetMetadata(string file)
public Dictionary<string, string> GetMetadata(string file, bool isSymlink, bool followSymlink)
{
var f = NoSnapshot.NormalizePath(file);
var dict = new Dictionary<string, string>();
var n = UnixSupport.File.GetExtendedAttributes(f);
var n = UnixSupport.File.GetExtendedAttributes(f, isSymlink, followSymlink);
if (n != null)
foreach(var x in n)
dict["unix-ext:" + x.Key] = Convert.ToBase64String(x.Value);
@@ -500,7 +500,7 @@ namespace Duplicati.Library.Snapshots
Alphaleonis.Win32.Filesystem.Directory.SetAccessControl(PrefixWithUNC(path), rules, AccessControlSections.All);
}
public Dictionary<string, string> GetMetadata(string path)
public Dictionary<string, string> GetMetadata(string path, bool isSymlink, bool followSymlink)
{
var isDirTarget = path.EndsWith(DIRSEP);
var targetpath = isDirTarget ? path.Substring(0, path.Length - 1) : path;
@@ -394,9 +394,11 @@ namespace Duplicati.Library.Snapshots
/// </summary>
/// <returns>The metadata for the given file or folder</returns>
/// <param name="file">The file or folder to examine</param>
public Dictionary<string, string> GetMetadata(string file)
/// <param name="isSymlink">A flag indicating if the target is a symlink</param>
/// <param name="followSymlink">A flag indicating if a symlink should be followed</param>
public Dictionary<string, string> GetMetadata(string file, bool isSymlink, bool followSymlink)
{
return _ioWin.GetMetadata(GetSnapshotPath(file));
return _ioWin.GetMetadata(GetSnapshotPath(file), isSymlink, followSymlink);
}
/// <summary>
@@ -116,14 +116,27 @@ then
exit $EXIT_CODE
fi
#
# Find filesystem used on $DEVICE.
# XFS filesystems need to be mounted with option -o nouuid.
# Other filesystems do not support that option.
#
FILESYSTEM=`df -PT /dev/"$DEVICE" | tail -1 | awk '{print $2}'`
if [ "$FILESYSTEM" == "xfs" ]; then
MOUNT_OPTIONS="ro,nouuid"
else
MOUNT_OPTIONS="ro"
fi
#
# Mount the snapshot on the mount point
#
mount -o ro "$LV_SNAPSHOT" "$TMPDIR"
mount -o "$MOUNT_OPTIONS" "$LV_SNAPSHOT" "$TMPDIR"
if [ "$?" -ne 0 ]
then
EXIT_CODE=$?
echo "Error: mount -o ro \"$LV_SNAPSHOT\" \"$TMPDIR\" failed!"
echo "Error: mount -o \"$MOUNTOPTIONS\" \"$LV_SNAPSHOT\" \"$TMPDIR\" failed!"
#We have created the volume, so remove it before exit
lvremove --force "$LV_GROUP/$NAME"
@@ -134,4 +147,4 @@ fi
# Report back to the caller what the name of the snapshot volume is
#
echo "tmpdir=\"$TMPDIR\""
exit 0
exit 0
+1 -1
View File
@@ -151,7 +151,7 @@
<a href="#/restoredirect" class="restore" translate>Restore backup</a>
</li>
<li ng-show="state.programState == 'Running'">
<a href class="pause" id="contextmenulink_pause" translate><span>Pause</span></a>
<a href class="pause" id="contextmenulink_pause"><span translate>Pause</span></a>
<ul class="contextmenu" id="contextmenu_pause">
<li>
@@ -518,7 +518,7 @@ body {
> a.pause {
background: url('../img/mainmenu/pause.png') no-repeat 8px 7px;
span {
> span {
padding-right: 25px;
background: url('../img/mainmenu/arrow_right.png') right center no-repeat;
}
@@ -550,7 +550,7 @@ body {
> a.pause.active {
background: @lColor url('../img/mainmenu/over/pause.png') no-repeat 8px 7px;
span {
> span {
background: url('../img/mainmenu/over/arrow_right.png') right center no-repeat;
}
}
File diff suppressed because one or more lines are too long
@@ -23,7 +23,7 @@ backupApp.controller('SystemSettingsController', function($rootScope, $scope, $l
var exp = new Date(now.getFullYear()+10, now.getMonth(), now.getDate());
$cookies.put('ui-locale', $scope.uiLanguage, { expires: exp });
gettextCatalog.setCurrentLanguage($scope.uiLanguage);
gettextCatalog.setCurrentLanguage($scope.uiLanguage.replace("-", "_"));
}
$rootScope.$broadcast('ui_language_changed');
}
@@ -117,7 +117,7 @@ backupApp.service('SystemInfo', function($rootScope, $timeout, $cookies, AppServ
if ((uiLanguage || '').trim().length == 0) {
gettextCatalog.setCurrentLanguage(state.BrowserLocale.Code.replace("-", "_"));
} else {
gettextCatalog.setCurrentLanguage(uiLanguage);
gettextCatalog.setCurrentLanguage(uiLanguage.replace("-", "_"));
}
}
+1 -1
View File
File diff suppressed because one or more lines are too long
@@ -34,7 +34,7 @@
<input class="submit" type="button" ng-click="doExport()" value="{{'Export configuration' | translate}} &gt;" />
</div>
<div ng-show="NoLocalDB">
<div ng-hide="NoLocalDB">
<h2 translate>Delete remote files</h2>
<div ng-show="Backup.Backup.Metadata.TargetFilesCount == null" translate>Loading remote storage usage ...</div>
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -1,4 +1,4 @@
#!/bin/bash
# transifex client in PATH necessary
cd $( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )
tx pull --language=de,fr,es
tx pull --language=de,fr,es,zh_CN
File diff suppressed because it is too large Load Diff
+103 -95
View File
@@ -4,8 +4,8 @@ using Mono.Unix.Native;
namespace UnixSupport
{
public static class File
{
public static class File
{
private static readonly bool SUPPORTS_LLISTXATTR;
@@ -27,81 +27,81 @@ namespace UnixSupport
SUPPORTS_LLISTXATTR = works;
}
/// <summary>
/// Opens the file and honors advisory locking.
/// </summary>
/// <returns>A open stream that references the file</returns>
/// <param name="path">The full path to the file</param>
public static System.IO.Stream OpenExclusive(string path, System.IO.FileAccess mode)
{
return OpenExclusive(path, mode, (int)Mono.Unix.Native.FilePermissions.DEFFILEMODE);
}
/// <summary>
/// Opens the file and honors advisory locking.
/// </summary>
/// <returns>A open stream that references the file</returns>
/// <param name="path">The full path to the file</param>
public static System.IO.Stream OpenExclusive(string path, System.IO.FileAccess mode)
{
return OpenExclusive(path, mode, (int)Mono.Unix.Native.FilePermissions.DEFFILEMODE);
}
/// <summary>
/// Opens the file and honors advisory locking.
/// </summary>
/// <returns>A open stream that references the file</returns>
/// <param name="path">The full path to the file</param>
/// <param name="filemode">The file create mode</param>
public static System.IO.Stream OpenExclusive(string path, System.IO.FileAccess mode, int filemode)
{
Flock lck;
lck.l_len = 0;
lck.l_pid = Syscall.getpid();
lck.l_start = 0;
lck.l_type = LockType.F_WRLCK;
lck.l_whence = SeekFlags.SEEK_SET;
OpenFlags flags = OpenFlags.O_CREAT;
if (mode == System.IO.FileAccess.Read)
{
lck.l_type = LockType.F_RDLCK;
flags |= OpenFlags.O_RDONLY;
} else if (mode == System.IO.FileAccess.Write) {
flags |= OpenFlags.O_WRONLY;
} else {
flags |= OpenFlags.O_RDWR;
}
int fd = Syscall.open(path, flags, (Mono.Unix.Native.FilePermissions)filemode);
if (fd > 0)
{
//This does not work on OSX, it gives ENOTTY
//int res = Syscall.fcntl(fd, Mono.Unix.Native.FcntlCommand.F_SETLK, ref lck);
//This is the same (at least for our purpose, and works on OSX)
int res = Syscall.lockf(fd, LockfCommand.F_TLOCK, 0);
/// <summary>
/// Opens the file and honors advisory locking.
/// </summary>
/// <returns>A open stream that references the file</returns>
/// <param name="path">The full path to the file</param>
/// <param name="filemode">The file create mode</param>
public static System.IO.Stream OpenExclusive(string path, System.IO.FileAccess mode, int filemode)
{
Flock lck;
lck.l_len = 0;
lck.l_pid = Syscall.getpid();
lck.l_start = 0;
lck.l_type = LockType.F_WRLCK;
lck.l_whence = SeekFlags.SEEK_SET;
OpenFlags flags = OpenFlags.O_CREAT;
if (mode == System.IO.FileAccess.Read)
{
lck.l_type = LockType.F_RDLCK;
flags |= OpenFlags.O_RDONLY;
} else if (mode == System.IO.FileAccess.Write) {
flags |= OpenFlags.O_WRONLY;
} else {
flags |= OpenFlags.O_RDWR;
}
int fd = Syscall.open(path, flags, (Mono.Unix.Native.FilePermissions)filemode);
if (fd > 0)
{
//This does not work on OSX, it gives ENOTTY
//int res = Syscall.fcntl(fd, Mono.Unix.Native.FcntlCommand.F_SETLK, ref lck);
//This is the same (at least for our purpose, and works on OSX)
int res = Syscall.lockf(fd, LockfCommand.F_TLOCK, 0);
//If we have the lock, return the stream
if (res == 0)
return new Mono.Unix.UnixStream(fd);
else
{
Mono.Unix.Native.Syscall.close(fd);
throw new LockedFileException(path, mode);
}
}
throw new BadFileException(path);
}
//If we have the lock, return the stream
if (res == 0)
return new Mono.Unix.UnixStream(fd);
else
{
Mono.Unix.Native.Syscall.close(fd);
throw new LockedFileException(path, mode);
}
}
throw new BadFileException(path);
}
[Serializable]
private class BadFileException : System.IO.IOException
{
public BadFileException(string filename)
: base(string.Format("Unable to open the file \"{0}\", error: {1} ({2})", filename, Syscall.GetLastError(), (int)Syscall.GetLastError()))
{
}
}
[Serializable]
private class BadFileException : System.IO.IOException
{
public BadFileException(string filename)
: base(string.Format("Unable to open the file \"{0}\", error: {1} ({2})", filename, Syscall.GetLastError(), (int)Syscall.GetLastError()))
{
}
}
[Serializable]
private class LockedFileException : System.IO.IOException
{
public LockedFileException(string filename, System.IO.FileAccess mode)
: base(string.Format("Unable to open the file \"{0}\" in mode {1}, error: {2} ({3})", filename, mode, Syscall.GetLastError(), (int)Syscall.GetLastError()))
{
}
}
[Serializable]
private class LockedFileException : System.IO.IOException
{
public LockedFileException(string filename, System.IO.FileAccess mode)
: base(string.Format("Unable to open the file \"{0}\" in mode {1}, error: {2} ({3})", filename, mode, Syscall.GetLastError(), (int)Syscall.GetLastError()))
{
}
}
[Serializable]
private class FileAccesException : System.IO.IOException
@@ -185,10 +185,18 @@ namespace UnixSupport
/// </summary>
/// <returns>The extended attributes.</returns>
/// <param name="path">The full path to look up</param>
public static Dictionary<string, byte[]> GetExtendedAttributes(string path)
/// <param name="isSymlink">A flag indicating if the target is a symlink</param>
/// <param name="followSymlink">A flag indicating if a symlink should be followed</param>
public static Dictionary<string, byte[]> GetExtendedAttributes(string path, bool isSymlink, bool followSymlink)
{
// If we get a symlink that we should not follow, we need llistxattr support
if (isSymlink && !followSymlink && !SUPPORTS_LLISTXATTR)
return null;
var use_llistxattr = SUPPORTS_LLISTXATTR && !followSymlink;
string[] values;
var size = SUPPORTS_LLISTXATTR ? Mono.Unix.Native.Syscall.llistxattr(path, out values) : Mono.Unix.Native.Syscall.listxattr(path, out values);
var size = use_llistxattr ? Mono.Unix.Native.Syscall.llistxattr(path, out values) : Mono.Unix.Native.Syscall.listxattr(path, out values);
if (size < 0)
{
// In case the underlying filesystem does not support extended attributes,
@@ -196,7 +204,7 @@ namespace UnixSupport
if (Syscall.GetLastError() == Errno.EOPNOTSUPP)
return null;
throw new FileAccesException(path, "llistxattr");
throw new FileAccesException(path, use_llistxattr ? "llistxattr" : "listxattr");
}
var dict = new Dictionary<string, byte[]>();
@@ -239,25 +247,25 @@ namespace UnixSupport
GID = fse.OwnerGroupId;
Permissions = (long)fse.FileAccessPermissions;
try
{
OwnerName = fse.OwnerUser.UserName;
}
catch (ArgumentException)
{
// Could not retrieve user name, possibly the user is not defined on the local system
OwnerName = null;
}
try
{
OwnerName = fse.OwnerUser.UserName;
}
catch (ArgumentException)
{
// Could not retrieve user name, possibly the user is not defined on the local system
OwnerName = null;
}
try
{
GroupName = fse.OwnerGroup.GroupName;
}
catch (ArgumentException)
{
// Could not retrieve group name, possibly the group is not defined on the local system
GroupName = null;
}
try
{
GroupName = fse.OwnerGroup.GroupName;
}
catch (ArgumentException)
{
// Could not retrieve group name, possibly the group is not defined on the local system
GroupName = null;
}
}
}
@@ -330,6 +338,6 @@ namespace UnixSupport
var fse = Mono.Unix.UnixFileInfo.GetFileSystemEntry(path);
return fse.Device + ":" + fse.Inode;
}
}
}
}
Binary file not shown.