1 package de.spiritscorp.datasync.model;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23 import java.io.IOException;
24 import java.nio.file.Files;
25 import java.nio.file.LinkOption;
26 import java.nio.file.Path;
27 import java.nio.file.StandardCopyOption;
28 import java.nio.file.attribute.DosFileAttributeView;
29 import java.nio.file.attribute.FileTime;
30 import java.nio.file.attribute.PosixFileAttributeView;
31 import java.nio.file.attribute.PosixFilePermission;
32 import java.util.EnumSet;
33 import java.util.List;
34 import java.util.Map;
35 import java.util.Set;
36 import java.util.concurrent.ExecutorService;
37 import java.util.concurrent.Executors;
38 import java.util.concurrent.TimeUnit;
39
40 import de.spiritscorp.datasync.ScanType;
41 import de.spiritscorp.datasync.io.Debug;
42 import de.spiritscorp.datasync.io.Logger;
43
44
45
46
47
48 class FileHandler {
49
50
51 private final Logger log;
52
53
54
55
56
57
58 FileHandler( final Logger logger ) {
59 this.log = logger;
60 }
61
62
63
64
65
66
67
68
69
70
71
72
73
74 void listFiles( final List<Path> paths, final Map<Path, FileAttributes> resultMap, final ScanType deepScan, final boolean subDir ) {
75 try( ExecutorService executor = Executors.newSingleThreadExecutor() ) {
76 for( final Path path : paths ) {
77
78 if( Thread.currentThread().isInterrupted() ) {
79 Debug.printDebug( "[File Handler] Interrupt! Interruption detected prior to walking directory path: %s", path.toString() );
80 executor.shutdownNow();
81 return;
82 }
83 if( Files.exists( path ) ) {
84 walkTree( path.normalize(), executor, resultMap, deepScan, subDir );
85 }
86 }
87 executor.shutdown();
88 while( !executor.awaitTermination( 100, TimeUnit.MILLISECONDS ) ) {
89 if( Thread.currentThread().isInterrupted() ) {
90 executor.shutdownNow();
91 return;
92 }
93 }
94 }catch( InterruptedException _ ) {
95 Debug.printDebug( "[File Handler] File processing walk subsystem was forcefully interrupted." );
96 Thread.currentThread().interrupt();
97 }
98 for( final Path path : paths ) {
99 Debug.printDebug( "[File Handler] ListFiles() -> ready %s -> %s", Thread.currentThread().getName(), path.toString() );
100 }
101 }
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120 void deleteFiles( final Map<Path, FileAttributes> map, final boolean logOn, final boolean trashbin, final Path trashbinPath ) {
121 for( final Map.Entry<Path, FileAttributes> entry : map.entrySet() ) {
122 final FileAttributes fileAttr = entry.getValue();
123 final Path path = entry.getKey();
124
125 if( Thread.currentThread().isInterrupted() ) {
126 Debug.printDebug( "[File Handler] Interrupt! Safe loop interruption caught within file deletion loop vector at: %s", path.toString() );
127 break;
128 }else if( fileAttr == null ) continue;
129 processSingleDeletion( path, fileAttr, trashbin, trashbinPath );
130 }
131 map.clear();
132 if( logOn ) log.printStatus();
133 }
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152 void copyFiles( final Map<Path, FileAttributes> map, final boolean logOn, final Path destPath ) {
153 for( final Map.Entry<Path, FileAttributes> entry : map.entrySet() ) {
154
155 if( Thread.currentThread().isInterrupted() ) {
156 Debug.printDebug( "[File Handler] Interrupt! Safe loop interruption caught within file replication loop vector at: %s", entry.getKey().toString() );
157 break;
158 }
159 final FileAttributes fileAttr = entry.getValue();
160 if( fileAttr == null ) continue;
161 final Path path = destPath.resolve( fileAttr.getRelativeFilePath() );
162
163 if( ensureWritable( path ) ) {
164 if( moveFile( entry.getKey(), path, fileAttr.getCreateTime() ) ) {
165 log.setEntry( path.toString(), "kopiert", fileAttr );
166 }else {
167 log.setEntry( path.toString(), "FEHLER BEIM KOPIEREN", fileAttr );
168 Debug.printDebug( "[File Handler Error] Copy failed: %s", path.toString() );
169 }
170 }else {
171 log.setEntry( path.toString(), "SCHREIBSCHUTZ BEIM KOPIEREN", fileAttr );
172 Debug.printDebug( "[File Handler Error] Copy failed, target file is not writable: %s", path.toString() );
173 }
174 }
175 map.clear();
176 if( logOn ) log.printStatus();
177 }
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193 private void processSingleDeletion( final Path path, final FileAttributes fileAttr, final boolean trashbin, final Path trashbinPath ) {
194 try {
195 if( trashbin && trashbinPath != null ) {
196 final Path trashbinFile = trashbinPath.resolve( fileAttr.getRelativeFilePath() );
197 if( !moveFile( path, trashbinFile, fileAttr.getCreateTime() ) ) {
198 log.setEntry( path.toString(), "FEHLER BEIM VERSCHIEBEN IN DEN PAPIERKORB", fileAttr );
199 Debug.printDebug( "[File Handler Error] Copy failed SourcePath :%s DestPath: %s", path.toString(), trashbinFile.toString() );
200 }
201 }
202 if( ensureWritable( path ) ) {
203 Files.delete( path );
204 log.setEntry( path.toString(), "gelöscht", fileAttr );
205 }else {
206 log.setEntry( path.toString(), "SCHREIBSCHUTZ BEIM LÖSCHEN", fileAttr );
207 Debug.printDebug( "[File Handler Error] Delete failed, target file is not writable: %s", path.toString() );
208 }
209 }catch( final IOException exception ) {
210 log.setEntry( path.toString(), "FEHLER BEIM LÖSCHEN", fileAttr );
211 Debug.printDebug( "[File Handler Error] Delete failed: %s", path.toString() );
212 Debug.printException( this.getClass(), exception );
213 }
214 }
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230 private boolean ensureWritable( final Path path ) {
231 if( !Files.exists( path, LinkOption.NOFOLLOW_LINKS ) ) return true;
232 if( Files.isWritable( path ) ) return true;
233 try {
234
235
236 final DosFileAttributeView dosView = Files.getFileAttributeView( path, DosFileAttributeView.class, LinkOption.NOFOLLOW_LINKS );
237 if( dosView != null ) {
238 dosView.setReadOnly( false );
239 return true;
240 }
241
242
243 final PosixFileAttributeView posixView = Files.getFileAttributeView( path, PosixFileAttributeView.class, LinkOption.NOFOLLOW_LINKS );
244 if( posixView != null ) {
245 final Set<PosixFilePermission> permissions = EnumSet.noneOf( PosixFilePermission.class );
246 permissions.addAll( posixView.readAttributes().permissions() );
247 if( permissions.add( PosixFilePermission.OWNER_WRITE ) ) {
248 posixView.setPermissions( permissions );
249 return true;
250 }
251 }
252
253 Debug.printDebug( "[File Handler] File system operations are not supported for this specific target track: %s", path.toString() );
254 }catch( final IOException exception ) {
255 Debug.printDebug( "[File Handler Error] I/O error, file permissions could not be verified or modified: %s", exception.getLocalizedMessage() );
256 Debug.printException( this.getClass(), exception );
257 }
258 return false;
259 }
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276 private boolean moveFile( final Path sourceFilePath, final Path destFilePath, final FileTime createTime ) {
277 if( destFilePath == null || sourceFilePath == null ) return false;
278 try {
279 if( !Files.exists( destFilePath ) ) Files.createDirectories( destFilePath.getParent() );
280 Files.copy( sourceFilePath, destFilePath, StandardCopyOption.REPLACE_EXISTING, StandardCopyOption.COPY_ATTRIBUTES );
281 Files.setAttribute( destFilePath, "creationTime", createTime );
282 return true;
283 }catch( IOException exception ) {
284 Debug.printException( this.getClass(), exception );
285 return false;
286 }
287 }
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303 private void walkTree( final Path path, final ExecutorService executor, final Map<Path, FileAttributes> resultMap, final ScanType deepScan, final boolean subDir ) {
304 try {
305 final Path baseDir = subDir ? path.getParent() : path;
306 Files.walkFileTree( path, new FileVisit( executor, baseDir, resultMap, deepScan ) );
307 }catch( final IOException exception ) {
308 Debug.printDebug( "[File Handler Error] Error on walking directory path: %s with message: %s", path.toString(), exception.getMessage() );
309 Debug.printException( this.getClass(), exception );
310 }
311 }
312
313 }