1 module unde.file_manager.remove_paths; 2 3 import unde.global_state; 4 import unde.lsblk; 5 import unde.lib; 6 import unde.scan; 7 import unde.path_mnt; 8 import unde.command_line.db; 9 10 import std.stdio; 11 import std.conv; 12 import core.stdc.stdlib; 13 import std.math; 14 import berkeleydb.all; 15 import std.stdint; 16 import core.stdc.stdlib; 17 import std..string; 18 import std.algorithm.sorting; 19 import std.utf; 20 import std.concurrency; 21 import core.time; 22 import core.thread; 23 import std.datetime; 24 25 import derelict.sdl2.sdl; 26 27 import std.file; 28 29 immutable DRect drect_zero = DRect(0, 0, 0, 0); 30 31 private void 32 save_errors(FMGlobalState rgs, PathMnt path, Exception e) 33 { 34 Dbt key, data; 35 string path0 = path.get_key(rgs.lsblk); 36 key = path0; 37 auto res = rgs.db_map.get(rgs.txn, &key, &data); 38 39 RectSize rectsize; 40 if (res == 0) 41 rectsize = data.to!(RectSize); 42 43 ulong curr_time = Clock.currTime().toUnixTime(); 44 rectsize.msg = to_char_array!80(strip_error(e.msg)); 45 rectsize.msg_time = curr_time; 46 rectsize.msg_color = 0x80FF8080; // ARGB 47 48 data = rectsize; 49 //writefln("WRITE - %s - %s", path0, rectsize); 50 res = rgs.db_map.put(rgs.txn, &key, &data); 51 if (res != 0) 52 throw new Exception("Path info to map-db not written"); 53 rgs.OIT++; 54 55 ssize_t first, last; 56 first = path0.indexOf("\0"); 57 while (first != last) 58 { 59 last = path0.lastIndexOf("\0"); 60 if (last > first) 61 path0 = path0[0..last]; 62 else 63 path0 = path0[0..first+1]; 64 key = path0; 65 res = rgs.db_map.get(rgs.txn, &key, &data); 66 if (res == 0) 67 { 68 rectsize = data.to!(RectSize); 69 70 if (curr_time > rectsize.newest_msg_time) 71 { 72 rectsize.newest_msg_time = curr_time; 73 74 data = rectsize; 75 //writefln("WRITE - %s - %s", path0, rectsize); 76 res = rgs.db_map.put(rgs.txn, &key, &data); 77 if (res != 0) 78 throw new Exception("Path info to map-db not written"); 79 rgs.OIT++; 80 } 81 } 82 } 83 } 84 85 private void 86 remove_and_save_errors(FMGlobalState rgs, PathMnt path, bool dir=false) 87 { 88 try 89 { 90 if (dir) 91 rmdir(path); 92 else 93 remove(path); 94 95 96 } 97 catch (FileException e) 98 { 99 save_errors(rgs, path, e); 100 } 101 } 102 103 package long 104 remove_path(FMGlobalState rgs, PathMnt path, bool root = true) 105 { 106 rgs.recommit(); 107 //writefln("remove_path(%s)", path); 108 // exits on exits of parent 109 receiveTimeout( 0.seconds, 110 (OwnerTerminated ot) { 111 writefln("Abort removing due stopping parent"); 112 rgs.finish = true; 113 } ); 114 115 if (rgs.finish) 116 return 0; 117 118 DirEntry de; 119 try 120 { 121 path.update(rgs.lsblk); 122 de = DirEntry(path); 123 } 124 catch (Exception e) 125 { 126 writefln("%s", e); 127 save_errors(rgs, path, e); 128 return 0; 129 } 130 131 if (root) 132 { 133 string path0 = path.get_key(rgs.lsblk); 134 foreach (char c; "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789") 135 { 136 string m = "" ~ c; 137 Dbt key, data; 138 key = m; 139 auto res = rgs.db_marks.get(null, &key, &data); 140 if (res == 0) 141 { 142 Mark mark = data.to!(Mark); 143 string mpath = from_char_array(mark.path); 144 if (mpath.startsWith(path0)) 145 { 146 res = rgs.db_marks.del(null, &key); 147 if (res != 0) 148 throw new Exception("Mark info to marks-db not deleted"); 149 } 150 } 151 } 152 } 153 154 if (de.isSymlink) 155 { 156 remove(path); 157 return 1; 158 } 159 else if (de.isDir) 160 { 161 string[] paths; 162 try 163 { 164 foreach (string name; dirEntries(path, SpanMode.shallow)) 165 { 166 paths ~= name; 167 } 168 } 169 catch (Exception e) 170 { 171 return 0; 172 } 173 174 sort!("a < b")(paths); 175 176 long files = 0; 177 foreach (string name; paths) 178 { 179 if (name != path) 180 { 181 long f = remove_path(rgs, path.next(name), false); 182 files += f; 183 184 } 185 } 186 187 remove_and_save_errors(rgs, path, true); 188 189 if (exists(path)) 190 { 191 Dbt key, data; 192 string path0 = path.get_key(rgs.lsblk); 193 key = path0; 194 //writefln("GET %s", info.uuid ~ subpath); 195 auto res = rgs.db_map.get(rgs.txn, &key, &data); 196 if (res == 0) 197 { 198 RectSize rectsize = data.to!(RectSize); 199 if ( rectsize.files >= files ) 200 { 201 rectsize.files -= files; 202 203 data = rectsize; 204 //writefln("WRITE - %s - %s", path0, rectsize); 205 res = rgs.db_map.put(rgs.txn, &key, &data); 206 if (res != 0) 207 throw new Exception("Path info to map-db not written"); 208 rgs.OIT++; 209 } 210 } 211 } 212 else 213 { 214 string path0 = path.get_key(rgs.lsblk); 215 216 writefln("path0=%s", path0); 217 Dbc cursor2; 218 cursor2 = rgs.db_command_output.cursor(rgs.txn, 0); 219 scope(exit) cursor2.close(); 220 221 Dbt key2, data2; 222 string ks = get_key_for_command_out(command_out_key(path0, 0, 0)); 223 key2 = ks; 224 auto res = cursor2.get(&key2, &data2, DB_SET_RANGE); 225 if (res == 0) 226 { 227 do 228 { 229 string key_string = key2.to!(string); 230 command_out_key cmd_out_key; 231 parse_key_for_command_out(key_string, cmd_out_key); 232 233 writefln("OUTPUT %s - %s", cmd_out_key.cwd, path0); 234 if (cmd_out_key.cwd == path0) 235 { 236 rgs.OIT++; 237 if (rgs.is_time_to_recommit()) 238 { 239 cursor2.close(); 240 rgs.recommit(); 241 cursor2 = rgs.db_command_output.cursor(rgs.txn, 0); 242 res = cursor2.get(&key2, &data2, DB_SET_RANGE); 243 if (res == DB_NOTFOUND) 244 { 245 goto out1; 246 } 247 } 248 249 cursor2.del(); 250 } 251 else 252 { 253 break; 254 } 255 256 } while (cursor2.get(&key2, &data2, DB_NEXT) == 0); 257 } 258 out1: 259 260 Dbc cursor3; 261 cursor3 = rgs.db_commands.cursor(rgs.txn, 0); 262 scope(exit) cursor3.close(); 263 264 Dbt key3, data3; 265 string ks3 = get_key_for_command(command_key(path0, 0)); 266 key3 = ks3; 267 res = cursor3.get(&key3, &data3, DB_SET_RANGE); 268 if (res == 0) 269 { 270 do 271 { 272 string key_string = key3.to!(string); 273 command_key cmd_key; 274 parse_key_for_command(key_string, cmd_key); 275 276 if (cmd_key.cwd == path0) 277 { 278 rgs.OIT++; 279 if (rgs.is_time_to_recommit()) 280 { 281 cursor3.close(); 282 rgs.recommit(); 283 cursor3 = rgs.db_commands.cursor(rgs.txn, 0); 284 res = cursor3.get(&key3, &data3, DB_SET_RANGE); 285 if (res == DB_NOTFOUND) 286 { 287 goto out2; 288 } 289 } 290 291 cursor3.del(); 292 } 293 else 294 { 295 break; 296 } 297 298 } while (cursor3.get(&key3, &data3, DB_NEXT) == 0); 299 } 300 301 out2: 302 Dbt key; 303 key = path0; 304 res = rgs.db_map.del(rgs.txn, &key); 305 if (res != 0) 306 { 307 throw new Exception("Path info from map-db not removed"); 308 } 309 rgs.OIT++; 310 } 311 return files; 312 } 313 else if (de.isFile) 314 { 315 remove_and_save_errors(rgs, path); 316 return 1; 317 } 318 else 319 { 320 remove_and_save_errors(rgs, path); 321 return 1; 322 } 323 } 324 325 private void 326 start_remove_paths(shared LsblkInfo[string] lsblk, immutable string[] paths, Tid tid) 327 { 328 writefln("Start removing %s", paths); 329 330 try { 331 FMGlobalState rgs = new FMGlobalState(); 332 scope(exit) 333 { 334 destroy(rgs); 335 } 336 337 rgs.lsblk = to!(LsblkInfo[string])(lsblk); 338 339 foreach(path; paths) 340 { 341 remove_path(rgs, PathMnt(rgs.lsblk, path)); 342 rgs.commit(); 343 } 344 } catch (shared(Throwable) exc) { 345 send(tid, exc); 346 } 347 348 writefln("Finish removing %s", paths); 349 send(tid, thisTid); 350 } 351 352 int remove_paths(GlobalState gs, immutable string[] paths) 353 { 354 foreach(tid, paths2; gs.removers) 355 { 356 if (paths2 == paths) 357 { 358 writefln("Remove Paths already in work"); 359 return 0; 360 } 361 } 362 363 shared LsblkInfo[string] lsblk = to!(shared LsblkInfo[string])(gs.lsblk); 364 auto tid = spawn(&start_remove_paths, lsblk, paths, thisTid); 365 gs.removers[tid] = paths.dup(); 366 return 0; 367 } 368 369 void check_removers(GlobalState gs) 370 { 371 // Look check_scanners 372 } 373