115
119
scheme = location.get_uri_scheme ();
116
120
is_trash = (scheme == "trash");
117
121
is_recent = (scheme == "recent");
118
is_no_info = ("cdda mtp".contains (scheme));
122
is_no_info = ("cdda mtp ssh sftp afp dav davs".contains (scheme)); //Try lifting requirement for info on remote connections
119
123
is_local = is_trash || is_recent || (scheme == "file");
120
124
is_network = !is_local && ("ftp sftp afp dav davs".contains (scheme));
121
125
can_open_files = !("mtp".contains (scheme));
122
126
can_stream_files = !("ftp sftp mtp dav davs".contains (scheme));
124
dir_cache_lock.@lock (); /* will always have been created via call to public static functions from_file () or from_gfile () */
125
directory_cache.insert (location.dup (), this);
126
dir_cache_lock.unlock ();
128
file_hash = new HashTable<GLib.File, GOF.File> (GLib.File.hash, GLib.File.equal);
128
130
this.add_toggle_ref ((ToggleNotify) toggle_ref_notify);
131
file_hash = new HashTable<GLib.File, GOF.File> (GLib.File.hash, GLib.File.equal);
187
194
warning ("Failed to get file info for file %s", file.uri);
200
debug ("success %s; enclosing mount %s", success.to_string (), file.mount != null ? file.mount.get_name () : "null");
190
201
yield make_ready (is_no_info || success, file_loaded_func); /* Only place that should call this function */
193
204
/*** Returns false if should be able to get info but were unable to ***/
194
205
private async bool get_file_info () {
195
/* Force info to be refreshed - the GOF.File may have been created already by another part of the program
196
* that did not ensure the correct info Aync purposes, and retrieved from cache (bug 1511307).
206
debug ("get_file_info");
200
208
if (is_network && !yield check_network ()) {
209
warning ("No network found");
201
210
file.is_connected = false;
206
/* Not a failure when not expected to get file info */
211
return file.ensure_query_info ();
214
/* is_network flag fails to detect remote folders mapped to a local uri through fstab, so treat
215
* all folders as potentially remote (and disconnected) */
214
217
if (!yield try_query_info ()) { /* may already be mounted */
218
debug ("try query info failed - trying to mount");
215
219
if (yield mount_mountable ()) {
216
220
/* Previously mounted Samba servers still appear mounted even if disconnected
217
221
* e.g. by unplugging the network cable. So the following function can block for
218
222
* a long time; we therefore use a timeout */
219
223
debug ("successful mount %s", file.uri);
220
return yield try_query_info ();
224
file.is_mounted = true;
225
return (yield try_query_info ()) || is_no_info;
227
warning ("failed mount %s", file.uri);
280
295
mount_op.ask_password.connect (() => {
296
debug ("Asking for password");
281
297
asking_password = true;
284
300
mount_op.reply.connect (() => {
301
debug ("Password dialog finished");
285
302
asking_password = false;
288
yield location.mount_enclosing_volume (0, mount_op, cancellable);
289
var mount = location.find_enclosing_mount ();
291
debug ("Found enclosing mount %s", mount != null ? mount.get_name () : "null");
292
return mount != null;
305
debug ("mounting ....");
306
res =yield location.mount_enclosing_volume (GLib.MountMountFlags.NONE, mount_op, cancellable);
293
307
} catch (Error e) {
308
last_error_message = e.message;
294
309
if (e is IOError.ALREADY_MOUNTED) {
295
310
debug ("Already mounted %s", file.uri);
296
311
file.is_connected = true;
297
313
} else if (e is IOError.NOT_FOUND) {
298
314
debug ("Enclosing mount not found %s (may be remote share)", file.uri);
299
file.is_mounted = false;
315
/* Do not fail loading at this point - may still load */
317
yield location.mount_mountable (GLib.MountMountFlags.NONE, mount_op, cancellable);
319
} catch (GLib.Error e2) {
320
last_error_message = e2.message;
321
warning ("Unable to mount mountable");
302
326
file.is_connected = false;
303
327
file.is_mounted = false;
328
debug ("Setting mount null 1");
304
330
warning ("Mount_mountable failed: %s", e.message);
305
331
if (e is IOError.PERMISSION_DENIED || e is IOError.FAILED_HANDLED) {
306
332
permission_denied = true;
311
336
cancel_timeout (ref mount_timeout_id);
339
debug ("success %s; enclosing mount %s", res.to_string (), file.mount != null ? file.mount.get_name () : "null");
315
343
public async bool check_network () {
344
debug ("check network");
316
345
var net_mon = GLib.NetworkMonitor.get_default ();
317
346
network_available = net_mon.get_network_available ();
319
348
bool success = false;
321
350
if (network_available) {
322
SocketConnectable? connectable = null;
324
connectable = NetworkAddress.parse_uri (file.uri, 21);
325
if (((NetworkAddress)(connectable)).get_hostname () != "" && scheme != "smb") {
326
success = net_mon.can_reach (connectable, cancellable);
327
/* Try to connect for real. This should time out after about 15 seconds if
328
* the host is not reachable */
329
var scl = new SocketClient ();
330
var sc = yield scl.connect_async (connectable, cancellable);
331
success = (sc != null && sc.is_connected ());
332
debug ("Attempt to connect to %s %s", file.uri, success ? "succeeded" : "failed");
351
if (!file.is_mounted) {
352
debug ("Network is available");
353
if (scheme != "smb") {
355
/* Try to connect for real. */
356
var scl = new SocketClient ();
357
scl.set_timeout (CONNECT_SOCKET_TIMEOUT_SEC);
358
scl.set_tls (PF.FileUtils.get_is_tls_for_protocol (scheme));
359
debug ("Trying to connect to connectable");
360
var sc = yield scl.connect_to_uri_async (file.uri, PF.FileUtils.get_default_port_for_protocol (scheme), cancellable);
361
success = (sc != null && sc.is_connected ());
362
debug ("Socketclient is %s", sc == null ? "null" : (sc.is_connected () ? "connected" : "not connected"));
363
} catch (GLib.Error e) {
364
last_error_message = e.message;
365
warning ("Error: could not connect to connectable %s - %s", file.uri, e.message);
337
catch (GLib.Error e) {
338
warning ("Error connecting to connectable %s - %s", file.uri, e.message);
372
debug ("File is already mounted - not reconnecting");
343
376
warning ("No network available");
380
debug ("Attempt to connect to %s %s", file.uri, success ? "succeeded" : "failed");
349
385
private async void make_ready (bool ready, GOFFileLoadedFunc? file_loaded_func = null) {
386
debug ("make ready");
350
387
can_load = ready;
352
389
warning ("%s cannot load. Connected %s, Mounted %s, Exists %s", file.uri,
353
390
file.is_connected.to_string (),
354
391
file.is_mounted.to_string (),
355
392
file.exists.to_string ());
356
state = State.NOT_LOADED; /* ensure state is correct */
393
after_loading (file_loaded_func);
398
/* Do not cache directory until it prepared and loadable to avoid an incorrect key being used in some
401
dir_cache_lock.@lock (); /* will always have been created via call to public static functions from_file () or from_gfile () */
402
directory_cache.insert (location.dup (), this);
403
dir_cache_lock.unlock ();
406
if (file.mount != null) {
407
debug ("Directory has mount point");
408
unowned GLib.List? trash_dirs = null;
409
trash_dirs = Marlin.FileOperations.get_trash_dirs_for_mount (file.mount);
410
has_trash_dirs = (trash_dirs != null);
412
has_trash_dirs = is_local;
363
415
yield list_directory_async (file_loaded_func);
513
572
state = State.LOADING;
514
bool show_hidden = is_trash || Preferences.get_default ().pref_show_hidden_files;
573
bool show_hidden = is_trash || Preferences.get_default ().show_hidden_files;
574
bool server_responding = false;
576
debug ("(Re)loading folder children"); /* Required for ctest */
517
579
/* This may hang for a long time if the connection was closed but is still mounted so we
518
580
* impose a time limit */
519
581
load_timeout_id = Timeout.add_seconds (ENUMERATE_TIMEOUT_SEC, () => {
520
cancellable.cancel ();
582
if (server_responding) {
585
debug ("Load timeout expired");
586
state = State.TIMED_OUT;
587
last_error_message = _("Server did not respond within time limit");
589
cancellable.cancel ();
525
595
var e = yield this.location.enumerate_children_async (gio_attrs, 0, Priority.HIGH, cancellable);
526
cancel_timeout (ref load_timeout_id);
596
debug ("Obtained file enumerator for location %s", location.get_uri ());
530
600
while (!cancellable.is_cancelled ()) {
531
var files = yield e.next_files_async (200, 0, cancellable);
535
foreach (var file_info in files) {
536
loc = location.get_child (file_info.get_name ());
537
assert (loc != null);
538
gof = GOF.File.cache_lookup (loc);
541
gof = new GOF.File (loc, location); /*does not add to GOF file cache */
602
server_responding = false;
603
var files = yield e.next_files_async (200, GLib.FileQueryInfoFlags.NOFOLLOW_SYMLINKS, cancellable);
604
server_responding = true;
609
foreach (var file_info in files) {
610
loc = location.get_child (file_info.get_name ());
611
assert (loc != null);
612
gof = GOF.File.cache_lookup (loc);
615
gof = new GOF.File (loc, location); /*does not add to GOF file cache */
618
gof.info = file_info;
621
file_hash.insert (gof.location, gof);
622
after_load_file (gof, show_hidden, file_loaded_func);
544
gof.info = file_info;
547
file_hash.insert (gof.location, gof);
548
after_load_file (gof, show_hidden, file_loaded_func);
627
last_error_message = e.message;
628
warning ("Error reported by next_files_async - %s", e.message);
553
state = State.LOADED;
631
/* Load as many files as we can get info for */
632
if (!(cancellable.is_cancelled ())) {
633
state = State.LOADED;
554
635
} catch (Error err) {
555
warning ("Listing directory error: %s %s", err.message, file.uri);
636
warning ("Listing directory error: %s, %s %s", last_error_message, err.message, file.uri);
556
637
can_load = false;
557
638
if (err is IOError.NOT_FOUND || err is IOError.NOT_DIRECTORY) {
558
639
file.exists = false;
559
} else if (err is IOError.PERMISSION_DENIED)
640
} else if (err is IOError.PERMISSION_DENIED) {
560
641
permission_denied = true;
561
else if (err is IOError.NOT_MOUNTED)
642
} else if (err is IOError.NOT_MOUNTED) {
562
644
file.is_mounted = false;
647
cancel_timeout (ref load_timeout_id);
648
after_loading (file_loaded_func);
565
after_loading (file_loaded_func);
568
652
private void after_load_file (GOF.File gof, bool show_hidden, GOFFileLoadedFunc? file_loaded_func) {
955
1044
if (file == null) {
956
1045
critical ("Null file received in Async cache_lookup");
958
1048
dir_cache_lock.@lock ();
959
1049
cached_dir = directory_cache.lookup (file);
1050
dir_cache_lock.unlock ();
961
1052
if (cached_dir != null) {
962
1053
if (cached_dir is Async && cached_dir.file != null) {
963
1054
debug ("found cached dir %s", cached_dir.file.uri);
964
if (cached_dir.file.info == null && cached_dir.can_load)
1055
if (cached_dir.file.info == null && cached_dir.can_load) {
1056
debug ("updating cached file info");
965
1057
cached_dir.file.query_update (); /* This is synchronous and causes blocking */
967
1060
warning ("Invalid directory found in cache");
968
1061
cached_dir = null;
1062
dir_cache_lock.@lock ();
969
1063
directory_cache.remove (file);
1064
dir_cache_lock.unlock ();
972
1067
debug ("Dir %s not in cache", file.get_uri ());
974
dir_cache_lock.unlock ();
976
1070
return cached_dir;