1
/* -*- Mode: Vala; indent-tabs-mode: nil; tab-width: 2 -*- */
3
This file is part of Déjà Dup.
4
For copyright information, see AUTHORS.
6
Déjà Dup is free software: you can redistribute it and/or modify
7
it under the terms of the GNU General Public License as published by
8
the Free Software Foundation, either version 3 of the License, or
9
(at your option) any later version.
11
Déjà Dup is distributed in the hope that it will be useful,
12
but WITHOUT ANY WARRANTY; without even the implied warranty of
13
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
GNU General Public License for more details.
16
You should have received a copy of the GNU General Public License
17
along with Déjà Dup. If not, see <http://www.gnu.org/licenses/>.
23
* Recursively moves one directory into another, merging files. And by merge,
24
* I mean it overwrites. It skips any files it can't move and reports an
25
* error, but keeps going.
27
* This is not optimized for remote files. It's mostly async, but it does the
28
* occasional sync operation.
30
internal class RecursiveMove : RecursiveOp
32
public RecursiveMove(File source, File dest)
34
Object(src: source, dst: dest);
37
void progress_callback(int64 current_num_bytes, int64 total_num_bytes)
39
// Do nothing right now
42
protected override void handle_file()
44
if (dst_type == FileType.DIRECTORY) {
45
// GIO will throw a fit if we try to overwrite a directory with a file.
46
// So cleanly delete directory first.
48
// We don't care about doing this 100% atomically, since user is
49
// intending to restore files to a previous state and implicitly doesn't
50
// worry about current state as long as we restore. It kinda sucks that
51
// we'd just delete a bunch of files and possibly not restore the original
52
// file, but chances are low that the following move will fail... But
53
// not guaranteed. It'd be nice to make this more perfect.
58
raise_error(src, dst, e.message);
65
FileCopyFlags.ALL_METADATA |
66
FileCopyFlags.NOFOLLOW_SYMLINKS |
67
FileCopyFlags.OVERWRITE,
71
catch (IOError.PERMISSION_DENIED e) {
72
// Try just copying it (in case we didn't have write access to src's
76
FileCopyFlags.ALL_METADATA |
77
FileCopyFlags.NOFOLLOW_SYMLINKS |
78
FileCopyFlags.OVERWRITE,
83
raise_error(src, dst, e.message);
87
raise_error(src, dst, e.message);
91
protected override void handle_dir()
93
if (dst_type != FileType.UNKNOWN && dst_type != FileType.DIRECTORY) {
94
// Hmmm... Something that's not a directory is in our way.
95
// Move dst file out of the way before we continue, else GIO will
98
// We don't care about doing this 100% atomically, since user is
99
// intending to restore files to a previous state and implicitly doesn't
100
// worry about current state as long as we restore. If we can delete
101
// it, we can create a directory in its place (i.e. restore of this
102
// directory is not likely to fail in a few seconds), so let's just blow
108
raise_error(src, dst, e.message);
112
dst_type = FileType.UNKNOWN; // now the file's gone
115
if (dst_type == FileType.UNKNOWN) {
116
// Create it. The GIO move function does not guarantee that we can move
117
// whole folders across filesystems. So we'll just create it and
118
// descend. Easy enough.
120
dst.make_directory(null);
123
raise_error(src, dst, e.message);
129
protected override void finish_dir()
131
// Now, we'll try to change it's settings to match our restore copy.
132
// If we tried to do this first, we may remove write access before trying
135
src.copy_attributes(dst,
136
FileCopyFlags.NOFOLLOW_SYMLINKS |
137
FileCopyFlags.ALL_METADATA,
141
// If we fail, no big deal. There'll often be stuff like /home that we
142
// can't change and don't care about changing.
146
src.@delete(null); // will only be deleted if empty, so we won't
147
// accidentally toss files left over from a failed
151
// Ignore. It's in /tmp, so it'll disappear, and most likely is just
152
// a non-empty directory.
156
protected override RecursiveOp clone_for_info(FileInfo info)
158
var child_name = info.get_name();
159
var src_child = src.get_child(child_name);
160
var dst_child = dst.get_child(child_name);
161
return new RecursiveMove(src_child, dst_child);