1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*-
2 
3    nemo-directory-async.c: Nemo directory model state machine.
4 
5    Copyright (C) 1999, 2000, 2001 Eazel, Inc.
6 
7    This program is free software; you can redistribute it and/or
8    modify it under the terms of the GNU General Public License as
9    published by the Free Software Foundation; either version 2 of the
10    License, or (at your option) any later version.
11 
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15    General Public License for more details.
16 
17    You should have received a copy of the GNU General Public
18    License along with this program; if not, write to the
19    Free Software Foundation, Inc., 51 Franklin Street - Suite 500,
20    Boston, MA 02110-1335, USA.
21 
22    Author: Darin Adler <darin@bentspoon.com>
23 */
24 
25 #include <config.h>
26 
27 #include "nemo-directory-notify.h"
28 #include "nemo-directory-private.h"
29 #include "nemo-file-attributes.h"
30 #include "nemo-file-private.h"
31 #include "nemo-file-utilities.h"
32 #include "nemo-signaller.h"
33 #include "nemo-global-preferences.h"
34 #include "nemo-link.h"
35 #include <eel/eel-glib-extensions.h>
36 #include <gtk/gtk.h>
37 #include <libxml/parser.h>
38 #include <stdio.h>
39 #include <stdlib.h>
40 #include <libxapp/xapp-favorites.h>
41 
42 /* turn this on to see messages about each load_directory call: */
43 #if 0
44 #define DEBUG_LOAD_DIRECTORY
45 #endif
46 
47 /* turn this on to check if async. job calls are balanced */
48 #if 0
49 #define DEBUG_ASYNC_JOBS
50 #endif
51 
52 /* turn this on to log things starting and stopping */
53 #if 0
54 #define DEBUG_START_STOP
55 #endif
56 
57 #define DIRECTORY_LOAD_ITEMS_PER_CALLBACK 100
58 
59 /* Keep async. jobs down to this number for all directories. */
60 #define MAX_ASYNC_JOBS 10
61 
62 struct LinkInfoReadState {
63 	NemoDirectory *directory;
64 	GCancellable *cancellable;
65 	NemoFile *file;
66 };
67 
68 struct ThumbnailState {
69 	NemoDirectory *directory;
70 	GCancellable *cancellable;
71 	NemoFile *file;
72 	gboolean trying_original;
73 	gboolean tried_original;
74 };
75 
76 struct MountState {
77 	NemoDirectory *directory;
78 	GCancellable *cancellable;
79 	NemoFile *file;
80 };
81 
82 struct FilesystemInfoState {
83 	NemoDirectory *directory;
84 	GCancellable *cancellable;
85 	NemoFile *file;
86 };
87 
88 struct DirectoryLoadState {
89 	NemoDirectory *directory;
90 	GCancellable *cancellable;
91 	GFileEnumerator *enumerator;
92 	GHashTable *load_mime_list_hash;
93 	NemoFile *load_directory_file;
94 	int load_file_count;
95 };
96 
97 struct MimeListState {
98 	NemoDirectory *directory;
99 	NemoFile *mime_list_file;
100 	GCancellable *cancellable;
101 	GFileEnumerator *enumerator;
102 	GHashTable *mime_list_hash;
103 };
104 
105 struct GetInfoState {
106 	NemoDirectory *directory;
107 	GCancellable *cancellable;
108 };
109 
110 struct GetBTimeState {
111     NemoDirectory *directory;
112     GCancellable *cancellable;
113 };
114 
115 struct NewFilesState {
116 	NemoDirectory *directory;
117 	GCancellable *cancellable;
118 	int count;
119 };
120 
121 struct DirectoryCountState {
122 	NemoDirectory *directory;
123 	NemoFile *count_file;
124 	GCancellable *cancellable;
125 	GFileEnumerator *enumerator;
126 	int file_count;
127 };
128 
129 struct DeepCountState {
130 	NemoDirectory *directory;
131 	GCancellable *cancellable;
132 	GFileEnumerator *enumerator;
133 	GFile *deep_count_location;
134 	GList *deep_count_subdirectories;
135 	GArray *seen_deep_count_inodes;
136 	char *fs_id;
137 };
138 
139 struct FavoriteCheckState {
140     NemoDirectory *directory;
141 };
142 
143 typedef struct {
144 	NemoFile *file; /* Which file, NULL means all. */
145 	union {
146 		NemoDirectoryCallback directory;
147 		NemoFileCallback file;
148 	} callback;
149 	gpointer callback_data;
150 	Request request;
151 	gboolean active; /* Set to FALSE when the callback is triggered and
152 			  * scheduled to be called at idle, its still kept
153 			  * in the list so we can kill it when the file
154 			  * goes away.
155 			  */
156 } ReadyCallback;
157 
158 typedef struct {
159 	NemoFile *file; /* Which file, NULL means all. */
160 	gboolean monitor_hidden_files; /* defines whether "all" includes hidden files */
161 	gconstpointer client;
162 	Request request;
163 } Monitor;
164 
165 typedef struct {
166 	NemoDirectory *directory;
167 	NemoInfoProvider *provider;
168 	NemoOperationHandle *handle;
169 	NemoOperationResult result;
170 } InfoProviderResponse;
171 
172 typedef gboolean (* RequestCheck) (Request);
173 typedef gboolean (* FileCheck) (NemoFile *);
174 
175 /* Current number of async. jobs. */
176 static int async_job_count;
177 static GHashTable *waiting_directories;
178 #ifdef DEBUG_ASYNC_JOBS
179 static GHashTable *async_jobs;
180 #endif
181 
182 /* Forward declarations for functions that need them. */
183 static void     deep_count_load                               (DeepCountState         *state,
184 							       GFile                  *location);
185 static gboolean request_is_satisfied                          (NemoDirectory      *directory,
186 							       NemoFile           *file,
187 							       Request                 request);
188 static void     cancel_loading_attributes                     (NemoDirectory      *directory,
189 							       NemoFileAttributes  file_attributes);
190 static void     add_all_files_to_work_queue                   (NemoDirectory      *directory);
191 static void     link_info_done                                (NemoDirectory      *directory,
192 							       NemoFile           *file,
193 							       const char             *uri,
194 							       const char             *name,
195 							       GIcon                  *icon,
196 							       gboolean                is_launcher,
197 							       gboolean                is_foreign);
198 static void     move_file_to_low_priority_queue               (NemoDirectory      *directory,
199 							       NemoFile           *file);
200 static void     move_file_to_extension_queue                  (NemoDirectory      *directory,
201 							       NemoFile           *file);
202 static void     nemo_directory_invalidate_file_attributes (NemoDirectory      *directory,
203 							       NemoFileAttributes  file_attributes);
204 
205 /* Some helpers for case-insensitive strings.
206  * Move to nemo-glib-extensions?
207  */
208 
209 static gboolean
istr_equal(gconstpointer v,gconstpointer v2)210 istr_equal (gconstpointer v, gconstpointer v2)
211 {
212 	return g_ascii_strcasecmp (v, v2) == 0;
213 }
214 
215 static guint
istr_hash(gconstpointer key)216 istr_hash (gconstpointer key)
217 {
218 	const char *p;
219 	guint h;
220 
221 	h = 0;
222 	for (p = key; *p != '\0'; p++) {
223 		h = (h << 5) - h + g_ascii_tolower (*p);
224 	}
225 
226 	return h;
227 }
228 
229 static GHashTable *
istr_set_new(void)230 istr_set_new (void)
231 {
232 	return g_hash_table_new_full (istr_hash, istr_equal, g_free, NULL);
233 }
234 
235 static void
istr_set_insert(GHashTable * table,const char * istr)236 istr_set_insert (GHashTable *table, const char *istr)
237 {
238 	char *key;
239 
240 	key = g_strdup (istr);
241 	g_hash_table_replace (table, key, key);
242 }
243 
244 static void
add_istr_to_list(gpointer key,gpointer value,gpointer callback_data)245 add_istr_to_list (gpointer key, gpointer value, gpointer callback_data)
246 {
247 	GList **list;
248 
249 	list = callback_data;
250 	*list = g_list_prepend (*list, g_strdup (key));
251 }
252 
253 static GList *
istr_set_get_as_list(GHashTable * table)254 istr_set_get_as_list (GHashTable *table)
255 {
256 	GList *list;
257 
258 	list = NULL;
259 	g_hash_table_foreach (table, add_istr_to_list, &list);
260 	return list;
261 }
262 
263 static void
istr_set_destroy(GHashTable * table)264 istr_set_destroy (GHashTable *table)
265 {
266 	g_hash_table_destroy (table);
267 }
268 
269 static void
request_counter_add_request(RequestCounter counter,Request request)270 request_counter_add_request (RequestCounter counter,
271 			     Request request)
272 {
273 	guint i;
274 
275 	for (i = 0; i < REQUEST_TYPE_LAST; i++) {
276 		if (REQUEST_WANTS_TYPE (request, i)) {
277 			counter[i]++;
278 		}
279 	}
280 }
281 
282 static void
request_counter_remove_request(RequestCounter counter,Request request)283 request_counter_remove_request (RequestCounter counter,
284 				Request request)
285 {
286 	guint i;
287 
288 	for (i = 0; i < REQUEST_TYPE_LAST; i++) {
289 		if (REQUEST_WANTS_TYPE (request, i)) {
290 			counter[i]--;
291 		}
292 	}
293 }
294 
295 #if 0
296 static void
297 nemo_directory_verify_request_counts (NemoDirectory *directory)
298 {
299 	GList *l;
300 	RequestCounter counters;
301 	int i;
302 	gboolean fail;
303 
304 	fail = FALSE;
305 	for (i = 0; i < REQUEST_TYPE_LAST; i ++) {
306 		counters[i] = 0;
307 	}
308 	for (l = directory->details->monitor_list; l != NULL; l = l->next) {
309 		Monitor *monitor = l->data;
310 		request_counter_add_request (counters, monitor->request);
311 	}
312 	for (i = 0; i < REQUEST_TYPE_LAST; i ++) {
313 		if (counters[i] != directory->details->monitor_counters[i]) {
314 			g_warning ("monitor counter for %i is wrong, expecting %d but found %d",
315 				   i, counters[i], directory->details->monitor_counters[i]);
316 			fail = TRUE;
317 		}
318 	}
319 	for (i = 0; i < REQUEST_TYPE_LAST; i ++) {
320 		counters[i] = 0;
321 	}
322 	for (l = directory->details->call_when_ready_list; l != NULL; l = l->next) {
323 		ReadyCallback *callback = l->data;
324 		request_counter_add_request (counters, callback->request);
325 	}
326 	for (i = 0; i < REQUEST_TYPE_LAST; i ++) {
327 		if (counters[i] != directory->details->call_when_ready_counters[i]) {
328 			g_warning ("call when ready counter for %i is wrong, expecting %d but found %d",
329 				   i, counters[i], directory->details->call_when_ready_counters[i]);
330 			fail = TRUE;
331 		}
332 	}
333 	g_assert (!fail);
334 }
335 #endif
336 
337 /* Start a job. This is really just a way of limiting the number of
338  * async. requests that we issue at any given time. Without this, the
339  * number of requests is unbounded.
340  */
341 static gboolean
async_job_start(NemoDirectory * directory,const char * job)342 async_job_start (NemoDirectory *directory,
343 		 const char *job)
344 {
345 #ifdef DEBUG_ASYNC_JOBS
346 	char *key;
347 #endif
348 
349 #ifdef DEBUG_START_STOP
350 	g_message ("starting %s in %p", job, directory->details->location);
351 #endif
352 
353 	g_assert (async_job_count >= 0);
354 	g_assert (async_job_count <= MAX_ASYNC_JOBS);
355 
356 	if (async_job_count >= MAX_ASYNC_JOBS) {
357 		if (waiting_directories == NULL) {
358 			waiting_directories = g_hash_table_new (NULL, NULL);
359 		}
360 
361 		g_hash_table_insert (waiting_directories,
362 				     directory,
363 				     directory);
364 
365 		return FALSE;
366 	}
367 
368 #ifdef DEBUG_ASYNC_JOBS
369 	{
370 		char *uri;
371 		if (async_jobs == NULL) {
372 			async_jobs = g_hash_table_new (g_str_hash, g_str_equal);
373 		}
374 		uri = nemo_directory_get_uri (directory);
375 		key = g_strconcat (uri, ": ", job, NULL);
376 		if (g_hash_table_lookup (async_jobs, key) != NULL) {
377 			g_warning ("same job twice: %s in %s",
378 				   job, uri);
379 		}
380 		g_free (uri);
381 		g_hash_table_insert (async_jobs, key, directory);
382 	}
383 #endif
384 
385 	async_job_count += 1;
386 	return TRUE;
387 }
388 
389 /* End a job. */
390 static void
async_job_end(NemoDirectory * directory,const char * job)391 async_job_end (NemoDirectory *directory,
392 	       const char *job)
393 {
394 #ifdef DEBUG_ASYNC_JOBS
395 	char *key;
396 	gpointer table_key, value;
397 #endif
398 
399 #ifdef DEBUG_START_STOP
400 	g_message ("stopping %s in %p", job, directory->details->location);
401 #endif
402 
403 	g_assert (async_job_count > 0);
404 
405 #ifdef DEBUG_ASYNC_JOBS
406 	{
407 		char *uri;
408 		uri = nemo_directory_get_uri (directory);
409 		g_assert (async_jobs != NULL);
410 		key = g_strconcat (uri, ": ", job, NULL);
411 		if (!g_hash_table_lookup_extended (async_jobs, key, &table_key, &value)) {
412 			g_warning ("ending job we didn't start: %s in %s",
413 				   job, uri);
414 		} else {
415 			g_hash_table_remove (async_jobs, key);
416 			g_free (table_key);
417 		}
418 		g_free (uri);
419 		g_free (key);
420 	}
421 #endif
422 
423 	async_job_count -= 1;
424 }
425 
426 /* Helper to get one value from a hash table. */
427 static void
get_one_value_callback(gpointer key,gpointer value,gpointer callback_data)428 get_one_value_callback (gpointer key, gpointer value, gpointer callback_data)
429 {
430 	gpointer *returned_value;
431 
432 	returned_value = callback_data;
433 	*returned_value = value;
434 }
435 
436 /* return a single value from a hash table. */
437 static gpointer
get_one_value(GHashTable * table)438 get_one_value (GHashTable *table)
439 {
440 	gpointer value;
441 
442 	value = NULL;
443 	if (table != NULL) {
444 		g_hash_table_foreach (table, get_one_value_callback, &value);
445 	}
446 	return value;
447 }
448 
449 /* Wake up directories that are "blocked" as long as there are job
450  * slots available.
451  */
452 static void
async_job_wake_up(void)453 async_job_wake_up (void)
454 {
455 	static gboolean already_waking_up = FALSE;
456 	gpointer value;
457 
458 	g_assert (async_job_count >= 0);
459 	g_assert (async_job_count <= MAX_ASYNC_JOBS);
460 
461 	if (already_waking_up) {
462 		return;
463 	}
464 
465 	already_waking_up = TRUE;
466 	while (async_job_count < MAX_ASYNC_JOBS) {
467 		value = get_one_value (waiting_directories);
468 		if (value == NULL) {
469 			break;
470 		}
471 		g_hash_table_remove (waiting_directories, value);
472 		nemo_directory_async_state_changed
473 			(NEMO_DIRECTORY (value));
474 	}
475 	already_waking_up = FALSE;
476 }
477 
478 static void
directory_count_cancel(NemoDirectory * directory)479 directory_count_cancel (NemoDirectory *directory)
480 {
481 	if (directory->details->count_in_progress != NULL) {
482 		g_cancellable_cancel (directory->details->count_in_progress->cancellable);
483 	}
484 }
485 
486 static void
deep_count_cancel(NemoDirectory * directory)487 deep_count_cancel (NemoDirectory *directory)
488 {
489 	if (directory->details->deep_count_in_progress != NULL) {
490 		g_assert (NEMO_IS_FILE (directory->details->deep_count_file));
491 
492 		g_cancellable_cancel (directory->details->deep_count_in_progress->cancellable);
493 
494 		directory->details->deep_count_file->details->deep_counts_status = NEMO_REQUEST_NOT_STARTED;
495 
496 		directory->details->deep_count_in_progress->directory = NULL;
497 		directory->details->deep_count_in_progress = NULL;
498 		directory->details->deep_count_file = NULL;
499 
500 		async_job_end (directory, "deep count");
501 	}
502 }
503 
504 static void
mime_list_cancel(NemoDirectory * directory)505 mime_list_cancel (NemoDirectory *directory)
506 {
507 	if (directory->details->mime_list_in_progress != NULL) {
508 		g_cancellable_cancel (directory->details->mime_list_in_progress->cancellable);
509 	}
510 }
511 
512 static void
link_info_cancel(NemoDirectory * directory)513 link_info_cancel (NemoDirectory *directory)
514 {
515 	if (directory->details->link_info_read_state != NULL) {
516 		g_cancellable_cancel (directory->details->link_info_read_state->cancellable);
517 		directory->details->link_info_read_state->directory = NULL;
518 		directory->details->link_info_read_state = NULL;
519 		async_job_end (directory, "link info");
520 	}
521 }
522 
523 static void
thumbnail_cancel(NemoDirectory * directory)524 thumbnail_cancel (NemoDirectory *directory)
525 {
526 	if (directory->details->thumbnail_state != NULL) {
527 		g_cancellable_cancel (directory->details->thumbnail_state->cancellable);
528 		directory->details->thumbnail_state->directory = NULL;
529 		directory->details->thumbnail_state = NULL;
530 		async_job_end (directory, "thumbnail");
531 	}
532 }
533 
534 static void
mount_cancel(NemoDirectory * directory)535 mount_cancel (NemoDirectory *directory)
536 {
537 	if (directory->details->mount_state != NULL) {
538 		g_cancellable_cancel (directory->details->mount_state->cancellable);
539 		directory->details->mount_state->directory = NULL;
540 		directory->details->mount_state = NULL;
541 		async_job_end (directory, "mount");
542 	}
543 }
544 
545 static void
file_info_cancel(NemoDirectory * directory)546 file_info_cancel (NemoDirectory *directory)
547 {
548 	if (directory->details->get_info_in_progress != NULL) {
549 		g_cancellable_cancel (directory->details->get_info_in_progress->cancellable);
550 		directory->details->get_info_in_progress->directory = NULL;
551 		directory->details->get_info_in_progress = NULL;
552 		directory->details->get_info_file = NULL;
553 
554 		async_job_end (directory, "file info");
555 	}
556 }
557 
558 static void
btime_cancel(NemoDirectory * directory)559 btime_cancel (NemoDirectory *directory)
560 {
561     if (directory->details->get_btime_in_progress != NULL) {
562         g_cancellable_cancel (directory->details->get_btime_in_progress->cancellable);
563         directory->details->get_btime_in_progress->directory = NULL;
564         directory->details->get_btime_in_progress = NULL;
565         directory->details->get_btime_file = NULL;
566 
567         async_job_end (directory, "get btime");
568     }
569 }
570 
571 static void
favorite_check_cancel(NemoDirectory * directory)572 favorite_check_cancel (NemoDirectory *directory)
573 {
574     if (directory->details->favorite_check_in_progress != NULL) {
575         if (directory->details->favorite_check_idle_id > 0) {
576             g_source_remove (directory->details->favorite_check_idle_id);
577             directory->details->favorite_check_idle_id = 0;
578         }
579 
580         directory->details->favorite_check_in_progress->directory = NULL;
581         g_free (directory->details->favorite_check_in_progress);
582         directory->details->favorite_check_in_progress = NULL;
583         directory->details->favorite_check_file = NULL;
584 
585         async_job_end (directory, "favorite check");
586     }
587 }
588 
589 static void
new_files_cancel(NemoDirectory * directory)590 new_files_cancel (NemoDirectory *directory)
591 {
592 	GList *l;
593 	NewFilesState *state;
594 
595 	if (directory->details->new_files_in_progress != NULL) {
596 		for (l = directory->details->new_files_in_progress; l != NULL; l = l->next) {
597 			state = l->data;
598 			g_cancellable_cancel (state->cancellable);
599 			state->directory = NULL;
600 		}
601 		g_list_free (directory->details->new_files_in_progress);
602 		directory->details->new_files_in_progress = NULL;
603 	}
604 
605     if (directory->details->new_files_in_progress_changes != NULL) {
606         g_list_free_full (directory->details->new_files_in_progress_changes,
607                           (GDestroyNotify) g_object_unref);
608         directory->details->new_files_in_progress_changes = NULL;
609     }
610 }
611 
612 static int
monitor_key_compare(gconstpointer a,gconstpointer data)613 monitor_key_compare (gconstpointer a,
614 		     gconstpointer data)
615 {
616 	const Monitor *monitor;
617 	const Monitor *compare_monitor;
618 
619 	monitor = a;
620 	compare_monitor = data;
621 
622 	if (monitor->client < compare_monitor->client) {
623 		return -1;
624 	}
625 	if (monitor->client > compare_monitor->client) {
626 		return +1;
627 	}
628 
629 	if (monitor->file < compare_monitor->file) {
630 		return -1;
631 	}
632 	if (monitor->file > compare_monitor->file) {
633 		return +1;
634 	}
635 
636 	return 0;
637 }
638 
639 static GList *
find_monitor(NemoDirectory * directory,NemoFile * file,gconstpointer client)640 find_monitor (NemoDirectory *directory,
641 	      NemoFile *file,
642 	      gconstpointer client)
643 {
644 	Monitor monitor;
645 
646 	monitor.client = client;
647 	monitor.file = file;
648 
649 	return g_list_find_custom (directory->details->monitor_list,
650 				   &monitor,
651 				   monitor_key_compare);
652 }
653 
654 static void
remove_monitor_link(NemoDirectory * directory,GList * link)655 remove_monitor_link (NemoDirectory *directory,
656 		     GList *link)
657 {
658 	Monitor *monitor;
659 
660 	if (link != NULL) {
661 		monitor = link->data;
662 		request_counter_remove_request (directory->details->monitor_counters,
663 						monitor->request);
664 		directory->details->monitor_list =
665 			g_list_remove_link (directory->details->monitor_list, link);
666 		g_free (monitor);
667 		g_list_free_1 (link);
668 	}
669 }
670 
671 static void
remove_monitor(NemoDirectory * directory,NemoFile * file,gconstpointer client)672 remove_monitor (NemoDirectory *directory,
673 		NemoFile *file,
674 		gconstpointer client)
675 {
676 	remove_monitor_link (directory, find_monitor (directory, file, client));
677 }
678 
679 Request
nemo_directory_set_up_request(NemoFileAttributes file_attributes)680 nemo_directory_set_up_request (NemoFileAttributes file_attributes)
681 {
682 	Request request;
683 
684 	request = 0;
685 
686 	if ((file_attributes & NEMO_FILE_ATTRIBUTE_DIRECTORY_ITEM_COUNT) != 0) {
687 		REQUEST_SET_TYPE (request, REQUEST_DIRECTORY_COUNT);
688 	}
689 
690 	if ((file_attributes & NEMO_FILE_ATTRIBUTE_DEEP_COUNTS) != 0) {
691 		REQUEST_SET_TYPE (request, REQUEST_DEEP_COUNT);
692 	}
693 
694 	if ((file_attributes & NEMO_FILE_ATTRIBUTE_DIRECTORY_ITEM_MIME_TYPES) != 0) {
695 		REQUEST_SET_TYPE (request, REQUEST_MIME_LIST);
696 	}
697 	if ((file_attributes & NEMO_FILE_ATTRIBUTE_INFO) != 0) {
698 		REQUEST_SET_TYPE (request, REQUEST_FILE_INFO);
699 	}
700 	if ((file_attributes & NEMO_FILE_ATTRIBUTE_BTIME) != 0) {
701         REQUEST_SET_TYPE (request, REQUEST_BTIME);
702     }
703 	if (file_attributes & NEMO_FILE_ATTRIBUTE_LINK_INFO) {
704 		REQUEST_SET_TYPE (request, REQUEST_FILE_INFO);
705 		REQUEST_SET_TYPE (request, REQUEST_LINK_INFO);
706 	}
707 
708 	if ((file_attributes & NEMO_FILE_ATTRIBUTE_EXTENSION_INFO) != 0) {
709 		REQUEST_SET_TYPE (request, REQUEST_EXTENSION_INFO);
710 	}
711 
712 	if (file_attributes & NEMO_FILE_ATTRIBUTE_THUMBNAIL) {
713 		REQUEST_SET_TYPE (request, REQUEST_THUMBNAIL);
714 		REQUEST_SET_TYPE (request, REQUEST_FILE_INFO);
715 	}
716 
717 	if (file_attributes & NEMO_FILE_ATTRIBUTE_MOUNT) {
718 		REQUEST_SET_TYPE (request, REQUEST_MOUNT);
719 		REQUEST_SET_TYPE (request, REQUEST_FILE_INFO);
720 	}
721 
722 	if (file_attributes & NEMO_FILE_ATTRIBUTE_FILESYSTEM_INFO) {
723 		REQUEST_SET_TYPE (request, REQUEST_FILESYSTEM_INFO);
724 	}
725 
726     if (file_attributes & NEMO_FILE_ATTRIBUTE_FAVORITE_CHECK) {
727         REQUEST_SET_TYPE (request, REQUEST_FAVORITE_CHECK);
728     }
729 
730 	return request;
731 }
732 
733 static void
mime_db_changed_callback(GObject * ignore,NemoDirectory * dir)734 mime_db_changed_callback (GObject *ignore, NemoDirectory *dir)
735 {
736 	NemoFileAttributes attrs;
737 
738 	g_assert (dir != NULL);
739 	g_assert (dir->details != NULL);
740 
741 	attrs = NEMO_FILE_ATTRIBUTE_INFO |
742 		NEMO_FILE_ATTRIBUTE_LINK_INFO |
743 		NEMO_FILE_ATTRIBUTE_DIRECTORY_ITEM_MIME_TYPES;
744 
745 	nemo_directory_force_reload_internal (dir, attrs);
746 }
747 
748 void
nemo_directory_monitor_add_internal(NemoDirectory * directory,NemoFile * file,gconstpointer client,gboolean monitor_hidden_files,NemoFileAttributes file_attributes,NemoDirectoryCallback callback,gpointer callback_data)749 nemo_directory_monitor_add_internal (NemoDirectory *directory,
750 					 NemoFile *file,
751 					 gconstpointer client,
752 					 gboolean monitor_hidden_files,
753 					 NemoFileAttributes file_attributes,
754 					 NemoDirectoryCallback callback,
755 					 gpointer callback_data)
756 {
757 	Monitor *monitor;
758 	GList *file_list;
759 
760 	g_assert (NEMO_IS_DIRECTORY (directory));
761 
762 	/* Replace any current monitor for this client/file pair. */
763 	remove_monitor (directory, file, client);
764 
765 	/* Add the new monitor. */
766 	monitor = g_new (Monitor, 1);
767 	monitor->file = file;
768 	monitor->monitor_hidden_files = monitor_hidden_files;
769 	monitor->client = client;
770 	monitor->request = nemo_directory_set_up_request (file_attributes);
771 
772 	if (file == NULL) {
773 		REQUEST_SET_TYPE (monitor->request, REQUEST_FILE_LIST);
774 	}
775 	directory->details->monitor_list =
776 		g_list_prepend (directory->details->monitor_list, monitor);
777 	request_counter_add_request (directory->details->monitor_counters,
778 				     monitor->request);
779 
780 	if (callback != NULL) {
781 		file_list = nemo_directory_get_file_list (directory);
782 		(* callback) (directory, file_list, callback_data);
783 		nemo_file_list_free (file_list);
784 	}
785 
786 	/* Start the "real" monitoring (FAM or whatever). */
787 	/* We always monitor the whole directory since in practice
788 	 * nemo almost always shows the whole directory anyway, and
789 	 * it allows us to avoid one file monitor per file in a directory.
790 	 */
791 	if (directory->details->monitor == NULL) {
792 		directory->details->monitor = nemo_monitor_directory (directory->details->location);
793 	}
794 
795 
796 	if (REQUEST_WANTS_TYPE (monitor->request, REQUEST_FILE_INFO) &&
797 	    directory->details->mime_db_monitor == 0) {
798 		directory->details->mime_db_monitor =
799 			g_signal_connect_object (nemo_signaller_get_current (),
800 						 "mime_data_changed",
801 						 G_CALLBACK (mime_db_changed_callback), directory, 0);
802 	}
803 
804 	/* Put the monitor file or all the files on the work queue. */
805 	if (file != NULL) {
806 		nemo_directory_add_file_to_work_queue (directory, file);
807 	} else {
808 		add_all_files_to_work_queue (directory);
809 	}
810 
811 	/* Kick off I/O. */
812 	nemo_directory_async_state_changed (directory);
813 }
814 
815 static void
set_file_unconfirmed(NemoFile * file,gboolean unconfirmed)816 set_file_unconfirmed (NemoFile *file, gboolean unconfirmed)
817 {
818 	NemoDirectory *directory;
819 
820 	g_assert (NEMO_IS_FILE (file));
821 	g_assert (unconfirmed == FALSE || unconfirmed == TRUE);
822 
823 	if (file->details->unconfirmed == unconfirmed) {
824 		return;
825 	}
826 	file->details->unconfirmed = unconfirmed;
827 
828 	directory = file->details->directory;
829 	if (unconfirmed) {
830 		directory->details->confirmed_file_count--;
831 	} else {
832 		directory->details->confirmed_file_count++;
833 	}
834 }
835 
836 static gboolean show_hidden_files = TRUE;
837 
838 static void
show_hidden_files_changed_callback(gpointer callback_data)839 show_hidden_files_changed_callback (gpointer callback_data)
840 {
841 	show_hidden_files = g_settings_get_boolean (nemo_preferences, NEMO_PREFERENCES_SHOW_HIDDEN_FILES);
842 }
843 
844 static gboolean
should_skip_file(NemoDirectory * directory,GFileInfo * info)845 should_skip_file (NemoDirectory *directory, GFileInfo *info)
846 {
847 	static gboolean show_hidden_files_changed_callback_installed = FALSE;
848 
849 	/* Add the callback once for the life of our process */
850 	if (!show_hidden_files_changed_callback_installed) {
851 		g_signal_connect_swapped (nemo_preferences,
852 					  "changed::" NEMO_PREFERENCES_SHOW_HIDDEN_FILES,
853 					  G_CALLBACK(show_hidden_files_changed_callback),
854 					  NULL);
855 
856 		show_hidden_files_changed_callback_installed = TRUE;
857 
858 		/* Peek for the first time */
859 		show_hidden_files_changed_callback (NULL);
860 	}
861 
862 	if (!show_hidden_files &&
863 	    (g_file_info_get_is_hidden (info) ||
864 	     g_file_info_get_is_backup (info))) {
865 		return TRUE;
866 	}
867 
868 	return FALSE;
869 }
870 
871 static void
process_files_changed_while_being_added(NemoDirectory * directory)872 process_files_changed_while_being_added (NemoDirectory *directory)
873 {
874     if (directory->details->new_files_in_progress_changes == NULL)
875     {
876         return;
877     }
878 
879     directory->details->new_files_in_progress_changes = g_list_reverse (directory->details->new_files_in_progress_changes);
880 
881     nemo_directory_notify_files_changed (directory->details->new_files_in_progress_changes);
882 
883     g_list_free_full (directory->details->new_files_in_progress_changes,
884                       (GDestroyNotify) g_object_unref);
885     directory->details->new_files_in_progress_changes = NULL;
886 }
887 
888 static gboolean
dequeue_pending_idle_callback(gpointer callback_data)889 dequeue_pending_idle_callback (gpointer callback_data)
890 {
891 	NemoDirectory *directory;
892 	GList *pending_file_info;
893 	GList *node, *next;
894 	NemoFile *file;
895 	GList *changed_files, *added_files;
896 	GFileInfo *file_info;
897 	const char *mimetype, *name;
898 	DirectoryLoadState *dir_load_state;
899 
900 	directory = NEMO_DIRECTORY (callback_data);
901 
902 	nemo_directory_ref (directory);
903 
904 	directory->details->dequeue_pending_idle_id = 0;
905 
906 	/* Handle the files in the order we saw them. */
907 	pending_file_info = g_list_reverse (directory->details->pending_file_info);
908 	directory->details->pending_file_info = NULL;
909 
910 	/* If we are no longer monitoring, then throw away these. */
911 	if (!nemo_directory_is_file_list_monitored (directory)) {
912 		nemo_directory_async_state_changed (directory);
913 		goto drain;
914 	}
915 
916 	added_files = NULL;
917 	changed_files = NULL;
918 
919 	dir_load_state = directory->details->directory_load_in_progress;
920 
921 	/* Build a list of NemoFile objects. */
922 	for (node = pending_file_info; node != NULL; node = node->next) {
923 		file_info = node->data;
924 
925 		name = g_file_info_get_name (file_info);
926 
927 		/* Update the file count. */
928 		/* FIXME bugzilla.gnome.org 45063: This could count a
929 		 * file twice if we get it from both load_directory
930 		 * and from new_files_callback. Not too hard to fix by
931 		 * moving this into the actual callback instead of
932 		 * waiting for the idle function.
933 		 */
934 		if (dir_load_state &&
935 		    !should_skip_file (directory, file_info)) {
936 			dir_load_state->load_file_count += 1;
937 
938 			/* Add the MIME type to the set. */
939 			mimetype = g_file_info_get_content_type (file_info);
940 			if (mimetype != NULL) {
941 				istr_set_insert (dir_load_state->load_mime_list_hash,
942 						 mimetype);
943 			}
944 		}
945 
946 		/* check if the file already exists */
947 		file = nemo_directory_find_file_by_name (directory, name);
948 		if (file != NULL) {
949 			/* file already exists in dir, check if we still need to
950 			 *  emit file_added or if it changed */
951 			set_file_unconfirmed (file, FALSE);
952 			if (!file->details->is_added) {
953 				/* We consider this newly added even if its in the list.
954 				 * This can happen if someone called nemo_file_get_by_uri()
955 				 * on a file in the folder before the add signal was
956 				 * emitted */
957 				nemo_file_ref (file);
958 				file->details->is_added = TRUE;
959 				added_files = g_list_prepend (added_files, file);
960 			} else if (nemo_file_update_info (file, file_info)) {
961 				/* File changed, notify about the change. */
962 				nemo_file_ref (file);
963 				changed_files = g_list_prepend (changed_files, file);
964 			}
965 		} else {
966 			/* new file, create a nemo file object and add it to the list */
967 			file = nemo_file_new_from_info (directory, file_info);
968 			nemo_directory_add_file (directory, file);
969 			file->details->is_added = TRUE;
970 			added_files = g_list_prepend (added_files, file);
971 		}
972 	}
973 
974 	/* If we are done loading, then we assume that any unconfirmed
975          * files are gone.
976 	 */
977 	if (directory->details->directory_loaded) {
978 		for (node = directory->details->file_list;
979 		     node != NULL; node = next) {
980 			file = NEMO_FILE (node->data);
981 			next = node->next;
982 
983 			if (file->details->unconfirmed) {
984 				nemo_file_ref (file);
985 				changed_files = g_list_prepend (changed_files, file);
986 
987 				nemo_file_mark_gone (file);
988 			}
989 		}
990 	}
991 
992 	/* Send the changed and added signals. */
993 	nemo_directory_emit_change_signals (directory, changed_files);
994 	nemo_file_list_free (changed_files);
995 	nemo_directory_emit_files_added (directory, added_files);
996 	nemo_file_list_free (added_files);
997 
998 	if (directory->details->directory_loaded &&
999 	    !directory->details->directory_loaded_sent_notification) {
1000 		/* Send the done_loading signal. */
1001 		nemo_directory_emit_done_loading (directory);
1002 
1003 		if (dir_load_state) {
1004 			file = dir_load_state->load_directory_file;
1005 
1006 			file->details->directory_count = dir_load_state->load_file_count;
1007 			file->details->directory_count_is_up_to_date = TRUE;
1008 			file->details->got_directory_count = TRUE;
1009 
1010 			file->details->got_mime_list = TRUE;
1011 			file->details->mime_list_is_up_to_date = TRUE;
1012 			g_list_free_full (file->details->mime_list, g_free);
1013 			file->details->mime_list = istr_set_get_as_list
1014 				(dir_load_state->load_mime_list_hash);
1015 
1016 			nemo_file_changed (file);
1017 		}
1018 
1019 		nemo_directory_async_state_changed (directory);
1020 
1021 		directory->details->directory_loaded_sent_notification = TRUE;
1022 	}
1023 
1024     /* Process changes received for files while they were still
1025      * being added. See Bug 703179 for a situation this happens. */
1026     process_files_changed_while_being_added (directory);
1027 
1028  drain:
1029 	g_list_free_full (pending_file_info, g_object_unref);
1030 
1031 	/* Get the state machine running again. */
1032 	nemo_directory_async_state_changed (directory);
1033 
1034 	nemo_directory_unref (directory);
1035 	return FALSE;
1036 }
1037 
1038 void
nemo_directory_schedule_dequeue_pending(NemoDirectory * directory)1039 nemo_directory_schedule_dequeue_pending (NemoDirectory *directory)
1040 {
1041 	if (directory->details->dequeue_pending_idle_id == 0) {
1042 		directory->details->dequeue_pending_idle_id
1043 			= g_idle_add (dequeue_pending_idle_callback, directory);
1044 	}
1045 }
1046 
1047 static void
directory_load_one(NemoDirectory * directory,GFileInfo * info)1048 directory_load_one (NemoDirectory *directory,
1049 		    GFileInfo *info)
1050 {
1051 	if (info == NULL) {
1052 		return;
1053 	}
1054 
1055 	if (g_file_info_get_name (info) == NULL) {
1056 		char *uri;
1057 
1058 		uri = nemo_directory_get_uri (directory);
1059 		g_warning ("Got GFileInfo with NULL name in %s, ignoring. This shouldn't happen unless the gvfs backend is broken.\n", uri);
1060 		g_free (uri);
1061 
1062 		return;
1063 	}
1064 
1065 	/* Arrange for the "loading" part of the work. */
1066 	g_object_ref (info);
1067 	directory->details->pending_file_info
1068 		= g_list_prepend (directory->details->pending_file_info, info);
1069 	nemo_directory_schedule_dequeue_pending (directory);
1070 }
1071 
1072 static void
directory_load_cancel(NemoDirectory * directory)1073 directory_load_cancel (NemoDirectory *directory)
1074 {
1075 	NemoFile *file;
1076 	DirectoryLoadState *state;
1077 
1078 	state = directory->details->directory_load_in_progress;
1079 	if (state != NULL) {
1080 		file = state->load_directory_file;
1081 		file->details->loading_directory = FALSE;
1082 		if (file->details->directory != directory) {
1083 			nemo_directory_async_state_changed (file->details->directory);
1084 		}
1085 
1086 		g_cancellable_cancel (state->cancellable);
1087 		state->directory = NULL;
1088 		directory->details->directory_load_in_progress = NULL;
1089 		async_job_end (directory, "file list");
1090 	}
1091 }
1092 
1093 static void
file_list_cancel(NemoDirectory * directory)1094 file_list_cancel (NemoDirectory *directory)
1095 {
1096 	directory_load_cancel (directory);
1097 
1098 	if (directory->details->dequeue_pending_idle_id != 0) {
1099 		g_source_remove (directory->details->dequeue_pending_idle_id);
1100 		directory->details->dequeue_pending_idle_id = 0;
1101 	}
1102 
1103 	if (directory->details->pending_file_info != NULL) {
1104 		g_list_free_full (directory->details->pending_file_info, g_object_unref);
1105 		directory->details->pending_file_info = NULL;
1106 	}
1107 }
1108 
1109 static void
directory_load_done(NemoDirectory * directory,GError * error)1110 directory_load_done (NemoDirectory *directory,
1111 		     GError *error)
1112 {
1113 	GList *node;
1114 
1115 	directory->details->directory_loaded = TRUE;
1116 	directory->details->directory_loaded_sent_notification = FALSE;
1117 
1118 	if (error != NULL) {
1119 		/* The load did not complete successfully. This means
1120 		 * we don't know the status of the files in this directory.
1121 		 * We clear the unconfirmed bit on each file here so that
1122 		 * they won't be marked "gone" later -- we don't know enough
1123 		 * about them to know whether they are really gone.
1124 		 */
1125 		for (node = directory->details->file_list;
1126 		     node != NULL; node = node->next) {
1127 			set_file_unconfirmed (NEMO_FILE (node->data), FALSE);
1128 		}
1129 
1130 		nemo_directory_emit_load_error (directory, error);
1131 	}
1132 
1133 	/* Call the idle function right away. */
1134 	if (directory->details->dequeue_pending_idle_id != 0) {
1135 		g_source_remove (directory->details->dequeue_pending_idle_id);
1136 	}
1137 	dequeue_pending_idle_callback (directory);
1138 
1139 	directory_load_cancel (directory);
1140 }
1141 
1142 void
nemo_directory_monitor_remove_internal(NemoDirectory * directory,NemoFile * file,gconstpointer client)1143 nemo_directory_monitor_remove_internal (NemoDirectory *directory,
1144 					    NemoFile *file,
1145 					    gconstpointer client)
1146 {
1147 	g_assert (NEMO_IS_DIRECTORY (directory));
1148 	g_assert (file == NULL || NEMO_IS_FILE (file));
1149 	g_assert (client != NULL);
1150 
1151 	remove_monitor (directory, file, client);
1152 
1153 	if (directory->details->monitor != NULL
1154 	    && directory->details->monitor_list == NULL) {
1155 		nemo_monitor_cancel (directory->details->monitor);
1156 		directory->details->monitor = NULL;
1157 	}
1158 
1159 	/* XXX - do we need to remove anything from the work queue? */
1160 
1161 	nemo_directory_async_state_changed (directory);
1162 }
1163 
1164 FileMonitors *
nemo_directory_remove_file_monitors(NemoDirectory * directory,NemoFile * file)1165 nemo_directory_remove_file_monitors (NemoDirectory *directory,
1166 					 NemoFile *file)
1167 {
1168 	GList *result, **list, *node, *next;
1169 	Monitor *monitor;
1170 
1171 	g_assert (NEMO_IS_DIRECTORY (directory));
1172 	g_assert (NEMO_IS_FILE (file));
1173 	g_assert (file->details->directory == directory);
1174 
1175 	result = NULL;
1176 
1177 	list = &directory->details->monitor_list;
1178 	for (node = directory->details->monitor_list; node != NULL; node = next) {
1179 		next = node->next;
1180 		monitor = node->data;
1181 
1182 		if (monitor->file == file) {
1183 			*list = g_list_remove_link (*list, node);
1184 			result = g_list_concat (node, result);
1185 			request_counter_remove_request (directory->details->monitor_counters,
1186 							monitor->request);
1187 		}
1188 	}
1189 
1190 	/* XXX - do we need to remove anything from the work queue? */
1191 
1192 	nemo_directory_async_state_changed (directory);
1193 
1194 	return (FileMonitors *) result;
1195 }
1196 
1197 void
nemo_directory_add_file_monitors(NemoDirectory * directory,NemoFile * file,FileMonitors * monitors)1198 nemo_directory_add_file_monitors (NemoDirectory *directory,
1199 				      NemoFile *file,
1200 				      FileMonitors *monitors)
1201 {
1202 	GList **list;
1203 	GList *l;
1204 	Monitor *monitor;
1205 
1206 	g_assert (NEMO_IS_DIRECTORY (directory));
1207 	g_assert (NEMO_IS_FILE (file));
1208 	g_assert (file->details->directory == directory);
1209 
1210 	if (monitors == NULL) {
1211 		return;
1212 	}
1213 
1214 	for (l = (GList *)monitors; l != NULL; l = l->next) {
1215 		monitor = l->data;
1216 		request_counter_add_request (directory->details->monitor_counters,
1217 					     monitor->request);
1218 	}
1219 
1220 	list = &directory->details->monitor_list;
1221 	*list = g_list_concat (*list, (GList *) monitors);
1222 
1223 	nemo_directory_add_file_to_work_queue (directory, file);
1224 
1225 	nemo_directory_async_state_changed (directory);
1226 }
1227 
1228 static int
ready_callback_key_compare(gconstpointer a,gconstpointer b)1229 ready_callback_key_compare (gconstpointer a, gconstpointer b)
1230 {
1231 	const ReadyCallback *callback_a, *callback_b;
1232 
1233 	callback_a = a;
1234 	callback_b = b;
1235 
1236 	if (callback_a->file < callback_b->file) {
1237 		return -1;
1238 	}
1239 	if (callback_a->file > callback_b->file) {
1240 		return 1;
1241 	}
1242 	if (callback_a->file == NULL) {
1243 		/* ANSI C doesn't allow ordered compares of function pointers, so we cast them to
1244 		 * normal pointers to make some overly pedantic compilers (*cough* HP-UX *cough*)
1245 		 * compile this. Of course, on any compiler where ordered function pointers actually
1246 		 * break this probably won't work, but at least it will compile on platforms where it
1247 		 * works, but stupid compilers won't let you use it.
1248 		 */
1249 		if ((void *)callback_a->callback.directory < (void *)callback_b->callback.directory) {
1250 			return -1;
1251 		}
1252 		if ((void *)callback_a->callback.directory > (void *)callback_b->callback.directory) {
1253 			return 1;
1254 		}
1255 	} else {
1256 		if ((void *)callback_a->callback.file < (void *)callback_b->callback.file) {
1257 			return -1;
1258 		}
1259 		if ((void *)callback_a->callback.file > (void *)callback_b->callback.file) {
1260 			return 1;
1261 		}
1262 	}
1263 	if (callback_a->callback_data < callback_b->callback_data) {
1264 		return -1;
1265 	}
1266 	if (callback_a->callback_data > callback_b->callback_data) {
1267 		return 1;
1268 	}
1269 	return 0;
1270 }
1271 
1272 static int
ready_callback_key_compare_only_active(gconstpointer a,gconstpointer b)1273 ready_callback_key_compare_only_active (gconstpointer a, gconstpointer b)
1274 {
1275 	const ReadyCallback *callback_a;
1276 
1277 	callback_a = a;
1278 
1279 	/* Non active callbacks never match */
1280 	if (!callback_a->active) {
1281 		return -1;
1282 	}
1283 
1284 	return ready_callback_key_compare (a, b);
1285 }
1286 
1287 static void
ready_callback_call(NemoDirectory * directory,const ReadyCallback * callback)1288 ready_callback_call (NemoDirectory *directory,
1289 		     const ReadyCallback *callback)
1290 {
1291 	GList *file_list;
1292 
1293 	/* Call the callback. */
1294 	if (callback->file != NULL) {
1295 		if (callback->callback.file) {
1296 			(* callback->callback.file) (callback->file,
1297 						     callback->callback_data);
1298 		}
1299 	} else if (callback->callback.directory != NULL) {
1300 		if (directory == NULL ||
1301 		    !REQUEST_WANTS_TYPE (callback->request, REQUEST_FILE_LIST)) {
1302 			file_list = NULL;
1303 		} else {
1304 			file_list = nemo_directory_get_file_list (directory);
1305 		}
1306 
1307 		/* Pass back the file list if the user was waiting for it. */
1308 		(* callback->callback.directory) (directory,
1309 						  file_list,
1310 						  callback->callback_data);
1311 
1312 		nemo_file_list_free (file_list);
1313 	}
1314 }
1315 
1316 void
nemo_directory_call_when_ready_internal(NemoDirectory * directory,NemoFile * file,NemoFileAttributes file_attributes,gboolean wait_for_file_list,NemoDirectoryCallback directory_callback,NemoFileCallback file_callback,gpointer callback_data)1317 nemo_directory_call_when_ready_internal (NemoDirectory *directory,
1318 					     NemoFile *file,
1319 					     NemoFileAttributes file_attributes,
1320 					     gboolean wait_for_file_list,
1321 					     NemoDirectoryCallback directory_callback,
1322 					     NemoFileCallback file_callback,
1323 					     gpointer callback_data)
1324 {
1325 	ReadyCallback callback;
1326 
1327 	g_assert (directory == NULL || NEMO_IS_DIRECTORY (directory));
1328 	g_assert (file == NULL || NEMO_IS_FILE (file));
1329 	g_assert (file != NULL || directory_callback != NULL);
1330 
1331 	/* Construct a callback object. */
1332 	callback.active = TRUE;
1333 	callback.file = file;
1334 	if (file == NULL) {
1335 		callback.callback.directory = directory_callback;
1336 	} else {
1337 		callback.callback.file = file_callback;
1338 	}
1339 	callback.callback_data = callback_data;
1340 	callback.request = nemo_directory_set_up_request (file_attributes);
1341 	if (wait_for_file_list) {
1342 		REQUEST_SET_TYPE (callback.request, REQUEST_FILE_LIST);
1343 	}
1344 
1345 	/* Handle the NULL case. */
1346 	if (directory == NULL) {
1347 		ready_callback_call (NULL, &callback);
1348 		return;
1349 	}
1350 
1351 	/* Check if the callback is already there. */
1352 	if (g_list_find_custom (directory->details->call_when_ready_list,
1353 				&callback,
1354 				ready_callback_key_compare_only_active) != NULL) {
1355 		if (file_callback != NULL && directory_callback != NULL) {
1356 			g_warning ("tried to add a new callback while an old one was pending");
1357 		}
1358 		/* NULL callback means, just read it. Conflicts are ok. */
1359 		return;
1360 	}
1361 
1362 	/* Add the new callback to the list. */
1363 	directory->details->call_when_ready_list = g_list_prepend
1364 		(directory->details->call_when_ready_list,
1365 		 g_memdup (&callback, sizeof (callback)));
1366 	request_counter_add_request (directory->details->call_when_ready_counters,
1367 				     callback.request);
1368 
1369 	/* Put the callback file or all the files on the work queue. */
1370 	if (file != NULL) {
1371 		nemo_directory_add_file_to_work_queue (directory, file);
1372 	} else {
1373 		add_all_files_to_work_queue (directory);
1374 	}
1375 
1376 	nemo_directory_async_state_changed (directory);
1377 }
1378 
1379 gboolean
nemo_directory_check_if_ready_internal(NemoDirectory * directory,NemoFile * file,NemoFileAttributes file_attributes)1380 nemo_directory_check_if_ready_internal (NemoDirectory *directory,
1381 					    NemoFile *file,
1382 					    NemoFileAttributes file_attributes)
1383 {
1384 	Request request;
1385 
1386 	g_assert (NEMO_IS_DIRECTORY (directory));
1387 
1388 	request = nemo_directory_set_up_request (file_attributes);
1389 	return request_is_satisfied (directory, file, request);
1390 }
1391 
1392 static void
remove_callback_link_keep_data(NemoDirectory * directory,GList * link)1393 remove_callback_link_keep_data (NemoDirectory *directory,
1394 				GList *link)
1395 {
1396 	ReadyCallback *callback;
1397 
1398 	callback = link->data;
1399 
1400 	directory->details->call_when_ready_list = g_list_remove_link
1401 		(directory->details->call_when_ready_list, link);
1402 
1403 	request_counter_remove_request (directory->details->call_when_ready_counters,
1404 					callback->request);
1405 	g_list_free_1 (link);
1406 }
1407 
1408 static void
remove_callback_link(NemoDirectory * directory,GList * link)1409 remove_callback_link (NemoDirectory *directory,
1410 		      GList *link)
1411 {
1412 	ReadyCallback *callback;
1413 
1414 	callback = link->data;
1415 	remove_callback_link_keep_data (directory, link);
1416 	g_free (callback);
1417 }
1418 
1419 void
nemo_directory_cancel_callback_internal(NemoDirectory * directory,NemoFile * file,NemoDirectoryCallback directory_callback,NemoFileCallback file_callback,gpointer callback_data)1420 nemo_directory_cancel_callback_internal (NemoDirectory *directory,
1421 					     NemoFile *file,
1422 					     NemoDirectoryCallback directory_callback,
1423 					     NemoFileCallback file_callback,
1424 					     gpointer callback_data)
1425 {
1426 	ReadyCallback callback;
1427 	GList *node;
1428 
1429 	if (directory == NULL) {
1430 		return;
1431 	}
1432 
1433 	g_assert (NEMO_IS_DIRECTORY (directory));
1434 	g_assert (file == NULL || NEMO_IS_FILE (file));
1435 	g_assert (file != NULL || directory_callback != NULL);
1436 	g_assert (file == NULL || file_callback != NULL);
1437 
1438 	/* Construct a callback object. */
1439 	callback.file = file;
1440 	if (file == NULL) {
1441 		callback.callback.directory = directory_callback;
1442 	} else {
1443 		callback.callback.file = file_callback;
1444 	}
1445 	callback.callback_data = callback_data;
1446 
1447 	/* Remove all queued callback from the list (including non-active). */
1448 	do {
1449 		node = g_list_find_custom (directory->details->call_when_ready_list,
1450 					   &callback,
1451 					   ready_callback_key_compare);
1452 		if (node != NULL) {
1453 			remove_callback_link (directory, node);
1454 
1455 			nemo_directory_async_state_changed (directory);
1456 		}
1457 	} while (node != NULL);
1458 }
1459 
1460 static void
new_files_state_unref(NewFilesState * state)1461 new_files_state_unref (NewFilesState *state)
1462 {
1463 	state->count--;
1464 
1465 	if (state->count == 0) {
1466 		if (state->directory) {
1467 			state->directory->details->new_files_in_progress =
1468 				g_list_remove (state->directory->details->new_files_in_progress,
1469 					       state);
1470 		}
1471 
1472 		g_object_unref (state->cancellable);
1473 		g_free (state);
1474 	}
1475 }
1476 
1477 static void
new_files_callback(GObject * source_object,GAsyncResult * res,gpointer user_data)1478 new_files_callback (GObject *source_object,
1479 		    GAsyncResult *res,
1480 		    gpointer user_data)
1481 {
1482 	NemoDirectory *directory;
1483 	GFileInfo *info;
1484 	NewFilesState *state;
1485 
1486 	state = user_data;
1487 
1488 	if (state->directory == NULL) {
1489 		/* Operation was cancelled. Bail out */
1490 		new_files_state_unref (state);
1491 		return;
1492 	}
1493 
1494 	directory = nemo_directory_ref (state->directory);
1495 
1496 	/* Queue up the new file. */
1497 	info = g_file_query_info_finish (G_FILE (source_object), res, NULL);
1498 	if (info != NULL) {
1499 		directory_load_one (directory, info);
1500 		g_object_unref (info);
1501 	}
1502 
1503 	new_files_state_unref (state);
1504 
1505 	nemo_directory_unref (directory);
1506 }
1507 
1508 void
nemo_directory_get_info_for_new_files(NemoDirectory * directory,GList * location_list)1509 nemo_directory_get_info_for_new_files (NemoDirectory *directory,
1510 					   GList *location_list)
1511 {
1512 	NewFilesState *state;
1513 	GFile *location;
1514 	GList *l;
1515 
1516 	if (location_list == NULL) {
1517 		return;
1518 	}
1519 
1520 	state = g_new (NewFilesState, 1);
1521 	state->directory = directory;
1522 	state->cancellable = g_cancellable_new ();
1523 	state->count = 0;
1524 
1525 	for (l = location_list; l != NULL; l = l->next) {
1526 		location = l->data;
1527 
1528 		state->count++;
1529 
1530 		g_file_query_info_async (location,
1531 					 NEMO_FILE_DEFAULT_ATTRIBUTES,
1532 					 0,
1533 					 G_PRIORITY_DEFAULT,
1534 					 state->cancellable,
1535 					 new_files_callback, state);
1536 	}
1537 
1538 	directory->details->new_files_in_progress
1539 		= g_list_prepend (directory->details->new_files_in_progress,
1540 				  state);
1541 }
1542 
1543 void
nemo_async_destroying_file(NemoFile * file)1544 nemo_async_destroying_file (NemoFile *file)
1545 {
1546 	NemoDirectory *directory;
1547 	gboolean changed;
1548 	GList *node, *next;
1549 	ReadyCallback *callback;
1550 	Monitor *monitor;
1551 
1552 	directory = file->details->directory;
1553 	changed = FALSE;
1554 
1555 	/* Check for callbacks. */
1556 	for (node = directory->details->call_when_ready_list; node != NULL; node = next) {
1557 		next = node->next;
1558 		callback = node->data;
1559 
1560 		if (callback->file == file) {
1561 			/* Client should have cancelled callback. */
1562 			if (callback->active) {
1563 				g_warning ("destroyed file has call_when_ready pending");
1564 			}
1565 			remove_callback_link (directory, node);
1566 			changed = TRUE;
1567 		}
1568 	}
1569 
1570 	/* Check for monitors. */
1571 	for (node = directory->details->monitor_list; node != NULL; node = next) {
1572 		next = node->next;
1573 		monitor = node->data;
1574 
1575 		if (monitor->file == file) {
1576 			/* Client should have removed monitor earlier. */
1577 			g_warning ("destroyed file still being monitored");
1578 			remove_monitor_link (directory, node);
1579 			changed = TRUE;
1580 		}
1581 	}
1582 
1583 	/* Check if it's a file that's currently being worked on.
1584 	 * If so, make that NULL so it gets canceled right away.
1585 	 */
1586 	if (directory->details->count_in_progress != NULL &&
1587 	    directory->details->count_in_progress->count_file == file) {
1588 		directory->details->count_in_progress->count_file = NULL;
1589 		changed = TRUE;
1590 	}
1591 	if (directory->details->deep_count_file == file) {
1592 		directory->details->deep_count_file = NULL;
1593 		changed = TRUE;
1594 	}
1595 	if (directory->details->mime_list_in_progress != NULL &&
1596 	    directory->details->mime_list_in_progress->mime_list_file == file) {
1597 		directory->details->mime_list_in_progress->mime_list_file = NULL;
1598 		changed = TRUE;
1599 	}
1600 	if (directory->details->get_info_file == file) {
1601 		directory->details->get_info_file = NULL;
1602 		changed = TRUE;
1603 	}
1604     if (directory->details->get_btime_file == file) {
1605         directory->details->get_btime_file = NULL;
1606         changed = TRUE;
1607     }
1608     if (directory->details->favorite_check_file == file) {
1609         directory->details->favorite_check_file = NULL;
1610         changed = TRUE;
1611     }
1612 	if (directory->details->link_info_read_state != NULL &&
1613 	    directory->details->link_info_read_state->file == file) {
1614 		directory->details->link_info_read_state->file = NULL;
1615 		changed = TRUE;
1616 	}
1617 	if (directory->details->extension_info_file == file) {
1618 		directory->details->extension_info_file = NULL;
1619 		changed = TRUE;
1620 	}
1621 
1622 	if (directory->details->thumbnail_state != NULL &&
1623 	    directory->details->thumbnail_state->file ==  file) {
1624 		directory->details->thumbnail_state->file = NULL;
1625 		changed = TRUE;
1626 	}
1627 
1628 	if (directory->details->mount_state != NULL &&
1629 	    directory->details->mount_state->file ==  file) {
1630 		directory->details->mount_state->file = NULL;
1631 		changed = TRUE;
1632 	}
1633 
1634 	if (directory->details->filesystem_info_state != NULL &&
1635 	    directory->details->filesystem_info_state->file == file) {
1636 		directory->details->filesystem_info_state->file = NULL;
1637 		changed = TRUE;
1638 	}
1639 
1640 	/* Let the directory take care of the rest. */
1641 	if (changed) {
1642 		nemo_directory_async_state_changed (directory);
1643 	}
1644 }
1645 
1646 static gboolean
lacks_directory_count(NemoFile * file)1647 lacks_directory_count (NemoFile *file)
1648 {
1649 	return !file->details->directory_count_is_up_to_date
1650 		&& nemo_file_should_show_directory_item_count (file);
1651 }
1652 
1653 static gboolean
should_get_directory_count_now(NemoFile * file)1654 should_get_directory_count_now (NemoFile *file)
1655 {
1656 	return lacks_directory_count (file)
1657 		&& !file->details->loading_directory;
1658 }
1659 
1660 static gboolean
lacks_info(NemoFile * file)1661 lacks_info (NemoFile *file)
1662 {
1663 	return !file->details->file_info_is_up_to_date
1664 		&& !file->details->is_gone;
1665 }
1666 
1667 static gboolean
lacks_btime(NemoFile * file)1668 lacks_btime (NemoFile *file)
1669 {
1670     return !file->details->btime_is_up_to_date
1671         && !file->details->is_gone;
1672 }
1673 
1674 static gboolean
lacks_favorite_check(NemoFile * file)1675 lacks_favorite_check (NemoFile *file)
1676 {
1677     return !file->details->favorite_checked
1678         && !file->details->is_gone;
1679 }
1680 
1681 static gboolean
lacks_filesystem_info(NemoFile * file)1682 lacks_filesystem_info (NemoFile *file)
1683 {
1684 	return nemo_file_is_directory (file) && !file->details->filesystem_info_is_up_to_date;
1685 }
1686 
1687 static gboolean
lacks_deep_count(NemoFile * file)1688 lacks_deep_count (NemoFile *file)
1689 {
1690 	return file->details->deep_counts_status != NEMO_REQUEST_DONE;
1691 }
1692 
1693 static gboolean
lacks_mime_list(NemoFile * file)1694 lacks_mime_list (NemoFile *file)
1695 {
1696 	return !file->details->mime_list_is_up_to_date;
1697 }
1698 
1699 static gboolean
should_get_mime_list(NemoFile * file)1700 should_get_mime_list (NemoFile *file)
1701 {
1702 	return lacks_mime_list (file)
1703 		&& !file->details->loading_directory;
1704 }
1705 
1706 static gboolean
lacks_link_info(NemoFile * file)1707 lacks_link_info (NemoFile *file)
1708 {
1709 	if (file->details->file_info_is_up_to_date &&
1710 	    !file->details->link_info_is_up_to_date) {
1711 		if (nemo_file_is_nemo_link (file)) {
1712 			return TRUE;
1713 		} else {
1714 			link_info_done (file->details->directory, file, NULL, NULL, NULL, FALSE, FALSE);
1715 			return FALSE;
1716 		}
1717 	} else {
1718 		return FALSE;
1719 	}
1720 }
1721 
1722 static gboolean
lacks_extension_info(NemoFile * file)1723 lacks_extension_info (NemoFile *file)
1724 {
1725     return file->details->load_deferred_attrs > NEMO_FILE_LOAD_DEFERRED_ATTRS_NO &&
1726         file->details->pending_info_providers != NULL;
1727 }
1728 
1729 static gboolean
lacks_thumbnail(NemoFile * file)1730 lacks_thumbnail (NemoFile *file)
1731 {
1732     return file->details->load_deferred_attrs > NEMO_FILE_LOAD_DEFERRED_ATTRS_NO &&
1733         nemo_file_should_show_thumbnail (file) &&
1734 		file->details->thumbnail_path != NULL &&
1735 		!file->details->thumbnail_is_up_to_date;
1736 }
1737 
1738 static gboolean
lacks_mount(NemoFile * file)1739 lacks_mount (NemoFile *file)
1740 {
1741 	return (!file->details->mount_is_up_to_date &&
1742 		(
1743 		 /* Unix mountpoint, could be a GMount */
1744 		 file->details->is_mountpoint ||
1745 
1746 		 /* The toplevel directory of something */
1747 		 (file->details->type == G_FILE_TYPE_DIRECTORY &&
1748 		  nemo_file_is_self_owned (file)) ||
1749 
1750 		 /* Mountable, could be a mountpoint */
1751 		 (file->details->type == G_FILE_TYPE_MOUNTABLE)
1752 
1753 		 )
1754 		);
1755 }
1756 
1757 static gboolean
has_problem(NemoDirectory * directory,NemoFile * file,FileCheck problem)1758 has_problem (NemoDirectory *directory, NemoFile *file, FileCheck problem)
1759 {
1760 	GList *node;
1761 
1762 	if (file != NULL) {
1763 		return (* problem) (file);
1764 	}
1765 
1766 	for (node = directory->details->file_list; node != NULL; node = node->next) {
1767 		if ((* problem) (node->data)) {
1768 			return TRUE;
1769 		}
1770 	}
1771 
1772 	return FALSE;
1773 }
1774 
1775 static gboolean
request_is_satisfied(NemoDirectory * directory,NemoFile * file,Request request)1776 request_is_satisfied (NemoDirectory *directory,
1777 		      NemoFile *file,
1778 		      Request request)
1779 {
1780 	if (REQUEST_WANTS_TYPE (request, REQUEST_FILE_LIST) &&
1781 	    !(directory->details->directory_loaded &&
1782 				    directory->details->directory_loaded_sent_notification)) {
1783 		return FALSE;
1784 	}
1785 
1786 	if (REQUEST_WANTS_TYPE (request, REQUEST_DIRECTORY_COUNT)) {
1787 		if (has_problem (directory, file, lacks_directory_count)) {
1788 			return FALSE;
1789 		}
1790 	}
1791 
1792 	if (REQUEST_WANTS_TYPE (request, REQUEST_FILE_INFO)) {
1793 		if (has_problem (directory, file, lacks_info)) {
1794 			return FALSE;
1795 		}
1796 	}
1797 
1798     if (REQUEST_WANTS_TYPE (request, REQUEST_BTIME)) {
1799         if (has_problem (directory, file, lacks_btime)) {
1800             return FALSE;
1801         }
1802     }
1803 
1804 	if (REQUEST_WANTS_TYPE (request, REQUEST_FILESYSTEM_INFO)) {
1805 		if (has_problem (directory, file, lacks_filesystem_info)) {
1806 			return FALSE;
1807 		}
1808 	}
1809 
1810 	if (REQUEST_WANTS_TYPE (request, REQUEST_DEEP_COUNT)) {
1811 		if (has_problem (directory, file, lacks_deep_count)) {
1812 			return FALSE;
1813 		}
1814 	}
1815 
1816 	if (REQUEST_WANTS_TYPE (request, REQUEST_THUMBNAIL)) {
1817 		if (has_problem (directory, file, lacks_thumbnail)) {
1818 			return FALSE;
1819 		}
1820 	}
1821 
1822 	if (REQUEST_WANTS_TYPE (request, REQUEST_MOUNT)) {
1823 		if (has_problem (directory, file, lacks_mount)) {
1824 			return FALSE;
1825 		}
1826 	}
1827 
1828 	if (REQUEST_WANTS_TYPE (request, REQUEST_MIME_LIST)) {
1829 		if (has_problem (directory, file, lacks_mime_list)) {
1830 			return FALSE;
1831 		}
1832 	}
1833 
1834 	if (REQUEST_WANTS_TYPE (request, REQUEST_LINK_INFO)) {
1835 		if (has_problem (directory, file, lacks_link_info)) {
1836 			return FALSE;
1837 		}
1838 	}
1839 
1840     if (REQUEST_WANTS_TYPE (request, REQUEST_FAVORITE_CHECK)) {
1841         if (has_problem (directory, file, lacks_favorite_check)) {
1842             return FALSE;
1843         }
1844     }
1845 
1846 	return TRUE;
1847 }
1848 
1849 static gboolean
call_ready_callbacks_at_idle(gpointer callback_data)1850 call_ready_callbacks_at_idle (gpointer callback_data)
1851 {
1852 	NemoDirectory *directory;
1853 	GList *node, *next;
1854 	ReadyCallback *callback;
1855 
1856 	directory = NEMO_DIRECTORY (callback_data);
1857 	directory->details->call_ready_idle_id = 0;
1858 
1859 	nemo_directory_ref (directory);
1860 
1861 	callback = NULL;
1862 	while (1) {
1863 		/* Check if any callbacks are non-active and call them if they are. */
1864 		for (node = directory->details->call_when_ready_list;
1865 		     node != NULL; node = next) {
1866 			next = node->next;
1867 			callback = node->data;
1868 			if (!callback->active) {
1869 				/* Non-active, remove and call */
1870 				break;
1871 			}
1872 		}
1873 		if (node == NULL) {
1874 			break;
1875 		}
1876 
1877 		/* Callbacks are one-shots, so remove it now. */
1878 		remove_callback_link_keep_data (directory, node);
1879 
1880 		/* Call the callback. */
1881 		ready_callback_call (directory, callback);
1882 		g_free (callback);
1883 	}
1884 
1885 	nemo_directory_async_state_changed (directory);
1886 
1887 	nemo_directory_unref (directory);
1888 
1889 	return FALSE;
1890 }
1891 
1892 static void
schedule_call_ready_callbacks(NemoDirectory * directory)1893 schedule_call_ready_callbacks (NemoDirectory *directory)
1894 {
1895 	if (directory->details->call_ready_idle_id == 0) {
1896 		directory->details->call_ready_idle_id
1897 			= g_idle_add (call_ready_callbacks_at_idle, directory);
1898 	}
1899 }
1900 
1901 /* Marks all callbacks that are ready as non-active and
1902  * calls them at idle time, unless they are removed
1903  * before then */
1904 static gboolean
call_ready_callbacks(NemoDirectory * directory)1905 call_ready_callbacks (NemoDirectory *directory)
1906 {
1907 	gboolean found_any;
1908 	GList *node, *next;
1909 	ReadyCallback *callback;
1910 
1911 	found_any = FALSE;
1912 
1913 	/* Check if any callbacks are satisifed and mark them for call them if they are. */
1914 	for (node = directory->details->call_when_ready_list;
1915 	     node != NULL; node = next) {
1916 		next = node->next;
1917 		callback = node->data;
1918 		if (callback->active &&
1919 		    request_is_satisfied (directory, callback->file, callback->request)) {
1920 			callback->active = FALSE;
1921 			found_any = TRUE;
1922 		}
1923 	}
1924 
1925 	if (found_any) {
1926 		schedule_call_ready_callbacks (directory);
1927 	}
1928 
1929 	return found_any;
1930 }
1931 
1932 gboolean
nemo_directory_has_active_request_for_file(NemoDirectory * directory,NemoFile * file)1933 nemo_directory_has_active_request_for_file (NemoDirectory *directory,
1934 						NemoFile *file)
1935 {
1936 	GList *node;
1937 	ReadyCallback *callback;
1938 	Monitor *monitor;
1939 
1940 	for (node = directory->details->call_when_ready_list;
1941 	     node != NULL; node = node->next) {
1942 		callback = node->data;
1943 		if (callback->file == file ||
1944 		    callback->file == NULL) {
1945 			return TRUE;
1946 		}
1947 	}
1948 
1949 	for (node = directory->details->monitor_list;
1950 	     node != NULL; node = node->next) {
1951 		monitor = node->data;
1952 		if (monitor->file == file ||
1953 		    monitor->file == NULL) {
1954 			return TRUE;
1955 		}
1956 	}
1957 
1958 	return FALSE;
1959 }
1960 
1961 
1962 /* This checks if there's a request for monitoring the file list. */
1963 gboolean
nemo_directory_is_anyone_monitoring_file_list(NemoDirectory * directory)1964 nemo_directory_is_anyone_monitoring_file_list (NemoDirectory *directory)
1965 {
1966 	if (directory->details->call_when_ready_counters[REQUEST_FILE_LIST] > 0) {
1967 		return TRUE;
1968 	}
1969 
1970 	if (directory->details->monitor_counters[REQUEST_FILE_LIST] > 0) {
1971 		return TRUE;
1972 	}
1973 
1974 	return FALSE;
1975 }
1976 
1977 /* This checks if the file list being monitored. */
1978 gboolean
nemo_directory_is_file_list_monitored(NemoDirectory * directory)1979 nemo_directory_is_file_list_monitored (NemoDirectory *directory)
1980 {
1981 	return directory->details->file_list_monitored;
1982 }
1983 
1984 static void
mark_all_files_unconfirmed(NemoDirectory * directory)1985 mark_all_files_unconfirmed (NemoDirectory *directory)
1986 {
1987 	GList *node;
1988 	NemoFile *file;
1989 
1990 	for (node = directory->details->file_list; node != NULL; node = node->next) {
1991 		file = node->data;
1992 		set_file_unconfirmed (file, TRUE);
1993 	}
1994 }
1995 
1996 static void
directory_load_state_free(DirectoryLoadState * state)1997 directory_load_state_free (DirectoryLoadState *state)
1998 {
1999 	if (state->enumerator) {
2000 		if (!g_file_enumerator_is_closed (state->enumerator)) {
2001 			g_file_enumerator_close_async (state->enumerator,
2002 						       0, NULL, NULL, NULL);
2003 		}
2004 		g_object_unref (state->enumerator);
2005 	}
2006 
2007 	if (state->load_mime_list_hash != NULL) {
2008 		istr_set_destroy (state->load_mime_list_hash);
2009 	}
2010 	nemo_file_unref (state->load_directory_file);
2011 	g_object_unref (state->cancellable);
2012 	g_free (state);
2013 }
2014 
2015 static void
more_files_callback(GObject * source_object,GAsyncResult * res,gpointer user_data)2016 more_files_callback (GObject *source_object,
2017 		     GAsyncResult *res,
2018 		     gpointer user_data)
2019 {
2020 	DirectoryLoadState *state;
2021 	NemoDirectory *directory;
2022 	GError *error;
2023 	GList *files, *l;
2024 	GFileInfo *info;
2025 
2026 	state = user_data;
2027 
2028 	if (state->directory == NULL) {
2029 		/* Operation was cancelled. Bail out */
2030 		directory_load_state_free (state);
2031 		return;
2032 	}
2033 
2034 	directory = nemo_directory_ref (state->directory);
2035 
2036 	g_assert (directory->details->directory_load_in_progress != NULL);
2037 	g_assert (directory->details->directory_load_in_progress == state);
2038 
2039 	error = NULL;
2040 	files = g_file_enumerator_next_files_finish (state->enumerator,
2041 						     res, &error);
2042 
2043 	for (l = files; l != NULL; l = l->next) {
2044 		info = l->data;
2045 		directory_load_one (directory, info);
2046 		g_object_unref (info);
2047 	}
2048 
2049 	if (files == NULL) {
2050 		directory_load_done (directory, error);
2051 		directory_load_state_free (state);
2052 	} else {
2053 		g_file_enumerator_next_files_async (state->enumerator,
2054 						    DIRECTORY_LOAD_ITEMS_PER_CALLBACK,
2055 						    G_PRIORITY_DEFAULT,
2056 						    state->cancellable,
2057 						    more_files_callback,
2058 						    state);
2059 	}
2060 
2061 	nemo_directory_unref (directory);
2062 
2063 	if (error) {
2064 		g_error_free (error);
2065 	}
2066 
2067 	g_list_free (files);
2068 }
2069 
2070 static void
enumerate_children_callback(GObject * source_object,GAsyncResult * res,gpointer user_data)2071 enumerate_children_callback (GObject *source_object,
2072 			     GAsyncResult *res,
2073 			     gpointer user_data)
2074 {
2075 	DirectoryLoadState *state;
2076 	GFileEnumerator *enumerator;
2077 	GError *error;
2078 
2079 	state = user_data;
2080 
2081 	if (state->directory == NULL) {
2082 		/* Operation was cancelled. Bail out */
2083 		directory_load_state_free (state);
2084 		return;
2085 	}
2086 
2087 	error = NULL;
2088 	enumerator = g_file_enumerate_children_finish  (G_FILE (source_object),
2089 							res, &error);
2090 
2091 	if (enumerator == NULL) {
2092 		directory_load_done (state->directory, error);
2093 		g_error_free (error);
2094 		directory_load_state_free (state);
2095 		return;
2096 	} else {
2097 		state->enumerator = enumerator;
2098 		g_file_enumerator_next_files_async (state->enumerator,
2099 						    DIRECTORY_LOAD_ITEMS_PER_CALLBACK,
2100 						    G_PRIORITY_DEFAULT,
2101 						    state->cancellable,
2102 						    more_files_callback,
2103 						    state);
2104 	}
2105 }
2106 
2107 
2108 /* Start monitoring the file list if it isn't already. */
2109 static void
start_monitoring_file_list(NemoDirectory * directory)2110 start_monitoring_file_list (NemoDirectory *directory)
2111 {
2112 	DirectoryLoadState *state;
2113 
2114 	if (!directory->details->file_list_monitored) {
2115 		g_assert (!directory->details->directory_load_in_progress);
2116 		directory->details->file_list_monitored = TRUE;
2117 		nemo_file_list_ref (directory->details->file_list);
2118 	}
2119 
2120 	if (directory->details->directory_loaded  ||
2121 	    directory->details->directory_load_in_progress != NULL) {
2122 		return;
2123 	}
2124 
2125 	if (!async_job_start (directory, "file list")) {
2126 		return;
2127 	}
2128 
2129 	mark_all_files_unconfirmed (directory);
2130 
2131 	state = g_new0 (DirectoryLoadState, 1);
2132 	state->directory = directory;
2133 	state->cancellable = g_cancellable_new ();
2134 	state->load_mime_list_hash = istr_set_new ();
2135 	state->load_file_count = 0;
2136 
2137 	g_assert (directory->details->location != NULL);
2138         state->load_directory_file =
2139 		nemo_directory_get_corresponding_file (directory);
2140 	state->load_directory_file->details->loading_directory = TRUE;
2141 
2142 #ifdef DEBUG_LOAD_DIRECTORY
2143 	g_message ("load_directory called to monitor file list of %p", directory->details->location);
2144 #endif
2145 
2146 	directory->details->directory_load_in_progress = state;
2147 
2148 	g_file_enumerate_children_async (directory->details->location,
2149 					 NEMO_FILE_DEFAULT_ATTRIBUTES,
2150 					 0, /* flags */
2151 					 G_PRIORITY_DEFAULT, /* prio */
2152 					 state->cancellable,
2153 					 enumerate_children_callback,
2154 					 state);
2155 }
2156 
2157 /* Stop monitoring the file list if it is being monitored. */
2158 void
nemo_directory_stop_monitoring_file_list(NemoDirectory * directory)2159 nemo_directory_stop_monitoring_file_list (NemoDirectory *directory)
2160 {
2161 	if (!directory->details->file_list_monitored) {
2162 		g_assert (directory->details->directory_load_in_progress == NULL);
2163 		return;
2164 	}
2165 
2166 	directory->details->file_list_monitored = FALSE;
2167 	file_list_cancel (directory);
2168 	nemo_file_list_unref (directory->details->file_list);
2169 	directory->details->directory_loaded = FALSE;
2170 }
2171 
2172 static void
file_list_start_or_stop(NemoDirectory * directory)2173 file_list_start_or_stop (NemoDirectory *directory)
2174 {
2175 	if (nemo_directory_is_anyone_monitoring_file_list (directory)) {
2176 		start_monitoring_file_list (directory);
2177 	} else {
2178 		nemo_directory_stop_monitoring_file_list (directory);
2179 	}
2180 }
2181 
2182 void
nemo_file_invalidate_count_and_mime_list(NemoFile * file)2183 nemo_file_invalidate_count_and_mime_list (NemoFile *file)
2184 {
2185 	NemoFileAttributes attributes;
2186 
2187 	attributes = NEMO_FILE_ATTRIBUTE_DIRECTORY_ITEM_COUNT |
2188 		NEMO_FILE_ATTRIBUTE_DIRECTORY_ITEM_MIME_TYPES;
2189 
2190 	nemo_file_invalidate_attributes (file, attributes);
2191 }
2192 
2193 
2194 /* Reset count and mime list. Invalidating deep counts is handled by
2195  * itself elsewhere because it's a relatively heavyweight and
2196  * special-purpose operation (see bug 5863). Also, the shallow count
2197  * needs to be refreshed when filtering changes, but the deep count
2198  * deliberately does not take filtering into account.
2199  */
2200 void
nemo_directory_invalidate_count_and_mime_list(NemoDirectory * directory)2201 nemo_directory_invalidate_count_and_mime_list (NemoDirectory *directory)
2202 {
2203 	NemoFile *file;
2204 
2205 	file = nemo_directory_get_existing_corresponding_file (directory);
2206 	if (file != NULL) {
2207 		nemo_file_invalidate_count_and_mime_list (file);
2208 	}
2209 
2210 	nemo_file_unref (file);
2211 }
2212 
2213 static void
nemo_directory_invalidate_file_attributes(NemoDirectory * directory,NemoFileAttributes file_attributes)2214 nemo_directory_invalidate_file_attributes (NemoDirectory      *directory,
2215 					       NemoFileAttributes  file_attributes)
2216 {
2217 	GList *node;
2218 
2219 	cancel_loading_attributes (directory, file_attributes);
2220 
2221 	for (node = directory->details->file_list; node != NULL; node = node->next) {
2222 		nemo_file_invalidate_attributes_internal (NEMO_FILE (node->data),
2223 							      file_attributes);
2224 	}
2225 
2226 	if (directory->details->as_file != NULL) {
2227 		nemo_file_invalidate_attributes_internal (directory->details->as_file,
2228 							      file_attributes);
2229 	}
2230 }
2231 
2232 void
nemo_directory_force_reload_internal(NemoDirectory * directory,NemoFileAttributes file_attributes)2233 nemo_directory_force_reload_internal (NemoDirectory     *directory,
2234 					  NemoFileAttributes file_attributes)
2235 {
2236 	/* invalidate attributes that are getting reloaded for all files */
2237 	nemo_directory_invalidate_file_attributes (directory, file_attributes);
2238 
2239 	/* Start a new directory load. */
2240 	file_list_cancel (directory);
2241 	directory->details->directory_loaded = FALSE;
2242 
2243 	/* Start a new directory count. */
2244 	nemo_directory_invalidate_count_and_mime_list (directory);
2245 
2246 	add_all_files_to_work_queue (directory);
2247 	nemo_directory_async_state_changed (directory);
2248 }
2249 
2250 static gboolean
monitor_includes_file(const Monitor * monitor,NemoFile * file)2251 monitor_includes_file (const Monitor *monitor,
2252 		       NemoFile *file)
2253 {
2254 	if (monitor->file == file) {
2255 		return TRUE;
2256 	}
2257 	if (monitor->file != NULL) {
2258 		return FALSE;
2259 	}
2260 	if (file == file->details->directory->details->as_file) {
2261 		return FALSE;
2262 	}
2263 	return nemo_file_should_show (file,
2264 					  monitor->monitor_hidden_files,
2265 					  TRUE);
2266 }
2267 
2268 static gboolean
is_needy(NemoFile * file,FileCheck check_missing,RequestType request_type_wanted)2269 is_needy (NemoFile *file,
2270 	  FileCheck check_missing,
2271 	  RequestType request_type_wanted)
2272 {
2273 	NemoDirectory *directory;
2274 	GList *node;
2275 	ReadyCallback *callback;
2276 	Monitor *monitor;
2277 
2278 	if (!(* check_missing) (file)) {
2279 		return FALSE;
2280 	}
2281 
2282 	directory = file->details->directory;
2283 	if (directory->details->call_when_ready_counters[request_type_wanted] > 0) {
2284 		for (node = directory->details->call_when_ready_list;
2285 		     node != NULL; node = node->next) {
2286 			callback = node->data;
2287 			if (callback->active &&
2288 			    REQUEST_WANTS_TYPE (callback->request, request_type_wanted)) {
2289 				if (callback->file == file) {
2290 					return TRUE;
2291 				}
2292 				if (callback->file == NULL
2293 				    && file != directory->details->as_file) {
2294 					return TRUE;
2295 				}
2296 			}
2297 		}
2298 	}
2299 
2300 	if (directory->details->monitor_counters[request_type_wanted] > 0) {
2301 		for (node = directory->details->monitor_list;
2302 		     node != NULL; node = node->next) {
2303 			monitor = node->data;
2304 			if (REQUEST_WANTS_TYPE (monitor->request, request_type_wanted)) {
2305 				if (monitor_includes_file (monitor, file)) {
2306 					return TRUE;
2307 				}
2308 			}
2309 		}
2310 	}
2311 	return FALSE;
2312 }
2313 
2314 static void
directory_count_stop(NemoDirectory * directory)2315 directory_count_stop (NemoDirectory *directory)
2316 {
2317 	NemoFile *file;
2318 
2319 	if (directory->details->count_in_progress != NULL) {
2320 		file = directory->details->count_in_progress->count_file;
2321 		if (file != NULL) {
2322 			g_assert (NEMO_IS_FILE (file));
2323 			g_assert (file->details->directory == directory);
2324 			if (is_needy (file,
2325 				      should_get_directory_count_now,
2326 				      REQUEST_DIRECTORY_COUNT)) {
2327 				return;
2328 			}
2329 		}
2330 
2331 		/* The count is not wanted, so stop it. */
2332 		directory_count_cancel (directory);
2333 	}
2334 }
2335 
2336 static guint
count_non_skipped_files(GList * list)2337 count_non_skipped_files (GList *list)
2338 {
2339 	guint count;
2340 	GList *node;
2341 	GFileInfo *info;
2342 
2343 	count = 0;
2344 	for (node = list; node != NULL; node = node->next) {
2345 		info = node->data;
2346 		if (!should_skip_file (NULL, info)) {
2347 			count += 1;
2348 		}
2349 	}
2350 	return count;
2351 }
2352 
2353 static void
count_children_done(NemoDirectory * directory,NemoFile * count_file,gboolean succeeded,int count)2354 count_children_done (NemoDirectory *directory,
2355 		     NemoFile *count_file,
2356 		     gboolean succeeded,
2357 		     int count)
2358 {
2359 	g_assert (NEMO_IS_FILE (count_file));
2360 
2361 	count_file->details->directory_count_is_up_to_date = TRUE;
2362 
2363 	/* Record either a failure or success. */
2364 	if (!succeeded) {
2365 		count_file->details->directory_count_failed = TRUE;
2366 		count_file->details->got_directory_count = FALSE;
2367 		count_file->details->directory_count = 0;
2368 	} else {
2369 		count_file->details->directory_count_failed = FALSE;
2370 		count_file->details->got_directory_count = TRUE;
2371 		count_file->details->directory_count = count;
2372 	}
2373 	directory->details->count_in_progress = NULL;
2374 
2375 	/* Send file-changed even if count failed, so interested parties can
2376 	 * distinguish between unknowable and not-yet-known cases.
2377 	 */
2378 	nemo_file_changed (count_file);
2379 
2380 	/* Start up the next one. */
2381 	async_job_end (directory, "directory count");
2382 	nemo_directory_async_state_changed (directory);
2383 }
2384 
2385 static void
directory_count_state_free(DirectoryCountState * state)2386 directory_count_state_free (DirectoryCountState *state)
2387 {
2388 	if (state->enumerator) {
2389 		if (!g_file_enumerator_is_closed (state->enumerator)) {
2390 			g_file_enumerator_close_async (state->enumerator,
2391 						       0, NULL, NULL, NULL);
2392 		}
2393 		g_object_unref (state->enumerator);
2394 	}
2395 	g_object_unref (state->cancellable);
2396 	nemo_directory_unref (state->directory);
2397 	g_free (state);
2398 }
2399 
2400 static void
count_more_files_callback(GObject * source_object,GAsyncResult * res,gpointer user_data)2401 count_more_files_callback (GObject *source_object,
2402 			   GAsyncResult *res,
2403 			   gpointer user_data)
2404 {
2405 	DirectoryCountState *state;
2406 	NemoDirectory *directory;
2407 	GError *error;
2408 	GList *files;
2409 
2410 	state = user_data;
2411 	directory = state->directory;
2412 
2413 	if (g_cancellable_is_cancelled (state->cancellable)) {
2414 		/* Operation was cancelled. Bail out */
2415 		directory->details->count_in_progress = NULL;
2416 
2417 		async_job_end (directory, "directory count");
2418 		nemo_directory_async_state_changed (directory);
2419 
2420 		directory_count_state_free (state);
2421 
2422 		return;
2423 	}
2424 
2425 	g_assert (directory->details->count_in_progress != NULL);
2426 	g_assert (directory->details->count_in_progress == state);
2427 
2428 	error = NULL;
2429 	files = g_file_enumerator_next_files_finish (state->enumerator,
2430 						     res, &error);
2431 
2432 	state->file_count += count_non_skipped_files (files);
2433 
2434 	if (files == NULL) {
2435 		count_children_done (directory, state->count_file,
2436 				     TRUE, state->file_count);
2437 		directory_count_state_free (state);
2438 	} else {
2439 		g_file_enumerator_next_files_async (state->enumerator,
2440 						    DIRECTORY_LOAD_ITEMS_PER_CALLBACK,
2441 						    G_PRIORITY_DEFAULT,
2442 						    state->cancellable,
2443 						    count_more_files_callback,
2444 						    state);
2445 	}
2446 
2447 	g_list_free_full (files, g_object_unref);
2448 
2449 	if (error) {
2450 		g_error_free (error);
2451 	}
2452 }
2453 
2454 static void
count_children_callback(GObject * source_object,GAsyncResult * res,gpointer user_data)2455 count_children_callback (GObject *source_object,
2456 			 GAsyncResult *res,
2457 			 gpointer user_data)
2458 {
2459 	DirectoryCountState *state;
2460 	GFileEnumerator *enumerator;
2461 	NemoDirectory *directory;
2462 	GError *error;
2463 
2464 	state = user_data;
2465 
2466 	if (g_cancellable_is_cancelled (state->cancellable)) {
2467 		/* Operation was cancelled. Bail out */
2468 		directory = state->directory;
2469 		directory->details->count_in_progress = NULL;
2470 
2471 		async_job_end (directory, "directory count");
2472 		nemo_directory_async_state_changed (directory);
2473 
2474 		directory_count_state_free (state);
2475 
2476 		return;
2477 	}
2478 
2479 	error = NULL;
2480 	enumerator = g_file_enumerate_children_finish  (G_FILE (source_object),
2481 							res, &error);
2482 
2483 	if (enumerator == NULL) {
2484 		count_children_done (state->directory,
2485 				     state->count_file,
2486 				     FALSE, 0);
2487 		g_error_free (error);
2488 		directory_count_state_free (state);
2489 		return;
2490 	} else {
2491 		state->enumerator = enumerator;
2492 		g_file_enumerator_next_files_async (state->enumerator,
2493 						    DIRECTORY_LOAD_ITEMS_PER_CALLBACK,
2494 						    G_PRIORITY_DEFAULT,
2495 						    state->cancellable,
2496 						    count_more_files_callback,
2497 						    state);
2498 	}
2499 }
2500 
2501 static void
directory_count_start(NemoDirectory * directory,NemoFile * file,gboolean * doing_io)2502 directory_count_start (NemoDirectory *directory,
2503 		       NemoFile *file,
2504 		       gboolean *doing_io)
2505 {
2506 	DirectoryCountState *state;
2507 	GFile *location;
2508 
2509 	if (directory->details->count_in_progress != NULL) {
2510 		*doing_io = TRUE;
2511 		return;
2512 	}
2513 
2514 	if (!is_needy (file,
2515 		       should_get_directory_count_now,
2516 		       REQUEST_DIRECTORY_COUNT)) {
2517 		return;
2518 	}
2519 	*doing_io = TRUE;
2520 
2521 	if (!nemo_file_is_directory (file)) {
2522 		file->details->directory_count_is_up_to_date = TRUE;
2523 		file->details->directory_count_failed = FALSE;
2524 		file->details->got_directory_count = FALSE;
2525 
2526 		nemo_directory_async_state_changed (directory);
2527 		return;
2528 	}
2529 
2530 	if (!async_job_start (directory, "directory count")) {
2531 		return;
2532 	}
2533 
2534 	/* Start counting. */
2535 	state = g_new0 (DirectoryCountState, 1);
2536 	state->count_file = file;
2537 	state->directory = nemo_directory_ref (directory);
2538 	state->cancellable = g_cancellable_new ();
2539 
2540 	directory->details->count_in_progress = state;
2541 
2542 	location = nemo_file_get_location (file);
2543 #ifdef DEBUG_LOAD_DIRECTORY
2544 	{
2545 		char *uri;
2546 		uri = g_file_get_uri (location);
2547 		g_message ("load_directory called to get shallow file count for %s", uri);
2548 		g_free (uri);
2549 	}
2550 #endif
2551 
2552 	g_file_enumerate_children_async (location,
2553 					 G_FILE_ATTRIBUTE_STANDARD_NAME ","
2554 					 G_FILE_ATTRIBUTE_STANDARD_IS_HIDDEN ","
2555 					 G_FILE_ATTRIBUTE_STANDARD_IS_BACKUP,
2556 					 G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, /* flags */
2557 					 G_PRIORITY_DEFAULT, /* prio */
2558 					 state->cancellable,
2559 					 count_children_callback,
2560 					 state);
2561 	g_object_unref (location);
2562 }
2563 
2564 static inline gboolean
seen_inode(DeepCountState * state,GFileInfo * info)2565 seen_inode (DeepCountState *state,
2566 	    GFileInfo *info)
2567 {
2568 	guint64 inode, inode2;
2569 	guint i;
2570 
2571 	inode = g_file_info_get_attribute_uint64 (info, G_FILE_ATTRIBUTE_UNIX_INODE);
2572 
2573 	if (inode != 0) {
2574 		for (i = 0; i < state->seen_deep_count_inodes->len; i++) {
2575 			inode2 = g_array_index (state->seen_deep_count_inodes, guint64, i);
2576 			if (inode == inode2) {
2577 				return TRUE;
2578 			}
2579 		}
2580 	}
2581 
2582 	return FALSE;
2583 }
2584 
2585 static inline void
mark_inode_as_seen(DeepCountState * state,GFileInfo * info)2586 mark_inode_as_seen (DeepCountState *state,
2587 		    GFileInfo *info)
2588 {
2589 	guint64 inode;
2590 
2591 	inode = g_file_info_get_attribute_uint64 (info, G_FILE_ATTRIBUTE_UNIX_INODE);
2592 	if (inode != 0) {
2593 		g_array_append_val (state->seen_deep_count_inodes, inode);
2594 	}
2595 }
2596 
2597 static void
deep_count_one(DeepCountState * state,GFileInfo * info)2598 deep_count_one (DeepCountState *state,
2599 		GFileInfo *info)
2600 {
2601 	NemoFile *file;
2602 	GFile *subdir;
2603 	gboolean is_seen_inode;
2604 	const char *id;
2605     gboolean hidden;
2606 	is_seen_inode = seen_inode (state, info);
2607 	if (!is_seen_inode) {
2608 		mark_inode_as_seen (state, info);
2609 	}
2610 
2611 	file = state->directory->details->deep_count_file;
2612 
2613     hidden = should_skip_file (NULL, info);
2614 
2615 	if (g_file_info_get_file_type (info) == G_FILE_TYPE_DIRECTORY) {
2616 		/* Count the directory. */
2617         if (hidden) {
2618             file->details->deep_hidden_count += 1;
2619         } else {
2620             file->details->deep_directory_count += 1;
2621         }
2622 		/* Record the fact that we have to descend into this directory. */
2623 		id = g_file_info_get_attribute_string (info, G_FILE_ATTRIBUTE_ID_FILESYSTEM);
2624 		if (g_strcmp0 (id, state->fs_id) == 0) {
2625 			/* only if it is on the same filesystem */
2626 			subdir = g_file_get_child (state->deep_count_location, g_file_info_get_name (info));
2627 			state->deep_count_subdirectories = g_list_prepend
2628 				(state->deep_count_subdirectories, subdir);
2629 		}
2630 	} else {
2631 		/* Even non-regular files count as files. */
2632         if (hidden) {
2633             file->details->deep_hidden_count += 1;
2634         } else {
2635             file->details->deep_file_count += 1;
2636         }
2637 	}
2638 
2639 	/* Count the size, hidden or not */
2640 	if (!is_seen_inode && g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_STANDARD_SIZE)) {
2641 		file->details->deep_size += g_file_info_get_size (info);
2642 	}
2643 }
2644 
2645 static void
deep_count_state_free(DeepCountState * state)2646 deep_count_state_free (DeepCountState *state)
2647 {
2648 	if (state->enumerator) {
2649 		if (!g_file_enumerator_is_closed (state->enumerator)) {
2650 			g_file_enumerator_close_async (state->enumerator,
2651 						       0, NULL, NULL, NULL);
2652 		}
2653 		g_object_unref (state->enumerator);
2654 	}
2655 	g_object_unref (state->cancellable);
2656 	if (state->deep_count_location) {
2657 		g_object_unref (state->deep_count_location);
2658 	}
2659 	g_list_free_full (state->deep_count_subdirectories, g_object_unref);
2660 	g_array_free (state->seen_deep_count_inodes, TRUE);
2661 	g_free (state->fs_id);
2662 	g_free (state);
2663 }
2664 
2665 static void
deep_count_next_dir(DeepCountState * state)2666 deep_count_next_dir (DeepCountState *state)
2667 {
2668 	GFile *location;
2669 	NemoFile *file;
2670 	NemoDirectory *directory;
2671 	gboolean done;
2672 
2673 	directory = state->directory;
2674 
2675 	g_object_unref (state->deep_count_location);
2676 	state->deep_count_location = NULL;
2677 
2678 	done = FALSE;
2679 	file = directory->details->deep_count_file;
2680 
2681 	if (state->deep_count_subdirectories != NULL) {
2682 		/* Work on a new directory. */
2683 		location = state->deep_count_subdirectories->data;
2684 		state->deep_count_subdirectories = g_list_remove
2685 			(state->deep_count_subdirectories, location);
2686 		deep_count_load (state, location);
2687 		g_object_unref (location);
2688 	} else {
2689 		file->details->deep_counts_status = NEMO_REQUEST_DONE;
2690 		directory->details->deep_count_file = NULL;
2691 		directory->details->deep_count_in_progress = NULL;
2692 		deep_count_state_free (state);
2693 		done = TRUE;
2694 	}
2695 
2696 	nemo_file_updated_deep_count_in_progress (file);
2697 
2698 	if (done) {
2699 		nemo_file_changed (file);
2700 		async_job_end (directory, "deep count");
2701 		nemo_directory_async_state_changed (directory);
2702 	}
2703 }
2704 
2705 static void
deep_count_more_files_callback(GObject * source_object,GAsyncResult * res,gpointer user_data)2706 deep_count_more_files_callback (GObject *source_object,
2707 				GAsyncResult *res,
2708 				gpointer user_data)
2709 {
2710 	DeepCountState *state;
2711 	NemoDirectory *directory;
2712 	GList *files, *l;
2713 	GFileInfo *info;
2714 
2715 	state = user_data;
2716 
2717 	if (state->directory == NULL) {
2718 		/* Operation was cancelled. Bail out */
2719 		deep_count_state_free (state);
2720 		return;
2721 	}
2722 
2723 	directory = nemo_directory_ref (state->directory);
2724 
2725 	g_assert (directory->details->deep_count_in_progress != NULL);
2726 	g_assert (directory->details->deep_count_in_progress == state);
2727 
2728 	files = g_file_enumerator_next_files_finish (state->enumerator,
2729 						     res, NULL);
2730 
2731 	for (l = files; l != NULL; l = l->next)	{
2732 		info = l->data;
2733 		deep_count_one (state, info);
2734 		g_object_unref (info);
2735 	}
2736 
2737 	if (files == NULL) {
2738 		g_file_enumerator_close_async (state->enumerator, 0, NULL, NULL, NULL);
2739 		g_object_unref (state->enumerator);
2740 		state->enumerator = NULL;
2741 
2742 		deep_count_next_dir (state);
2743 	} else {
2744 		g_file_enumerator_next_files_async (state->enumerator,
2745 						    DIRECTORY_LOAD_ITEMS_PER_CALLBACK,
2746 						    G_PRIORITY_LOW,
2747 						    state->cancellable,
2748 						    deep_count_more_files_callback,
2749 						    state);
2750 	}
2751 
2752 	g_list_free (files);
2753 
2754 	nemo_directory_unref (directory);
2755 }
2756 
2757 static void
deep_count_callback(GObject * source_object,GAsyncResult * res,gpointer user_data)2758 deep_count_callback (GObject *source_object,
2759 		     GAsyncResult *res,
2760 		     gpointer user_data)
2761 {
2762 	DeepCountState *state;
2763 	GFileEnumerator *enumerator;
2764 	NemoFile *file;
2765 
2766 	state = user_data;
2767 
2768 	if (state->directory == NULL) {
2769 		/* Operation was cancelled. Bail out */
2770 		deep_count_state_free (state);
2771 		return;
2772 	}
2773 
2774 	file = state->directory->details->deep_count_file;
2775 
2776 	enumerator = g_file_enumerate_children_finish  (G_FILE (source_object),	res, NULL);
2777 
2778 	if (enumerator == NULL) {
2779 		file->details->deep_unreadable_count += 1;
2780 
2781 		deep_count_next_dir (state);
2782 	} else {
2783 		state->enumerator = enumerator;
2784 		g_file_enumerator_next_files_async (state->enumerator,
2785 						    DIRECTORY_LOAD_ITEMS_PER_CALLBACK,
2786 						    G_PRIORITY_LOW,
2787 						    state->cancellable,
2788 						    deep_count_more_files_callback,
2789 						    state);
2790 	}
2791 }
2792 
2793 
2794 static void
deep_count_load(DeepCountState * state,GFile * location)2795 deep_count_load (DeepCountState *state, GFile *location)
2796 {
2797 	state->deep_count_location = g_object_ref (location);
2798 
2799 #ifdef DEBUG_LOAD_DIRECTORY
2800 	g_message ("load_directory called to get deep file count for %p", location);
2801 #endif
2802 	g_file_enumerate_children_async (state->deep_count_location,
2803 					 G_FILE_ATTRIBUTE_STANDARD_NAME ","
2804 					 G_FILE_ATTRIBUTE_STANDARD_TYPE ","
2805 					 G_FILE_ATTRIBUTE_STANDARD_SIZE ","
2806 					 G_FILE_ATTRIBUTE_STANDARD_IS_HIDDEN ","
2807 					 G_FILE_ATTRIBUTE_STANDARD_IS_BACKUP ","
2808 					 G_FILE_ATTRIBUTE_ID_FILESYSTEM ","
2809 					 G_FILE_ATTRIBUTE_UNIX_INODE,
2810 					 G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, /* flags */
2811 					 G_PRIORITY_LOW, /* prio */
2812 					 state->cancellable,
2813 					 deep_count_callback,
2814 					 state);
2815 }
2816 
2817 static void
deep_count_stop(NemoDirectory * directory)2818 deep_count_stop (NemoDirectory *directory)
2819 {
2820 	NemoFile *file;
2821 
2822 	if (directory->details->deep_count_in_progress != NULL) {
2823 		file = directory->details->deep_count_file;
2824 		if (file != NULL) {
2825 			g_assert (NEMO_IS_FILE (file));
2826 			g_assert (file->details->directory == directory);
2827 			if (is_needy (file,
2828 				      lacks_deep_count,
2829 				      REQUEST_DEEP_COUNT)) {
2830 				return;
2831 			}
2832 		}
2833 
2834 		/* The count is not wanted, so stop it. */
2835 		deep_count_cancel (directory);
2836 	}
2837 }
2838 
2839 static void
deep_count_got_info(GObject * source_object,GAsyncResult * res,gpointer user_data)2840 deep_count_got_info (GObject *source_object,
2841 		     GAsyncResult *res,
2842 		     gpointer user_data)
2843 {
2844 	GFileInfo *info;
2845 	const char *id;
2846 	GFile *file = (GFile *)source_object;
2847 	DeepCountState *state = (DeepCountState *)user_data;
2848 
2849 	info = g_file_query_info_finish (file,
2850 					 res,
2851 					 NULL);
2852 	if (info) {
2853 		id = g_file_info_get_attribute_string (info, G_FILE_ATTRIBUTE_ID_FILESYSTEM);
2854 		state->fs_id = g_strdup (id);
2855 		g_object_unref (info);
2856 	}
2857 	deep_count_load (state, file);
2858 }
2859 
2860 static void
deep_count_start(NemoDirectory * directory,NemoFile * file,gboolean * doing_io)2861 deep_count_start (NemoDirectory *directory,
2862 		  NemoFile *file,
2863 		  gboolean *doing_io)
2864 {
2865 	GFile *location;
2866 	DeepCountState *state;
2867 
2868 	if (directory->details->deep_count_in_progress != NULL) {
2869 		*doing_io = TRUE;
2870 		return;
2871 	}
2872 
2873 	if (!is_needy (file,
2874 		       lacks_deep_count,
2875 		       REQUEST_DEEP_COUNT)) {
2876 		return;
2877 	}
2878 	*doing_io = TRUE;
2879 
2880 	if (!nemo_file_is_directory (file)) {
2881 		file->details->deep_counts_status = NEMO_REQUEST_DONE;
2882 
2883 		nemo_directory_async_state_changed (directory);
2884 		return;
2885 	}
2886 
2887 	if (!async_job_start (directory, "deep count")) {
2888 		return;
2889 	}
2890 
2891 	/* Start counting. */
2892 	file->details->deep_counts_status = NEMO_REQUEST_IN_PROGRESS;
2893 	file->details->deep_directory_count = 0;
2894 	file->details->deep_file_count = 0;
2895 	file->details->deep_unreadable_count = 0;
2896     file->details->deep_hidden_count = 0;
2897 	file->details->deep_size = 0;
2898 	directory->details->deep_count_file = file;
2899 
2900 	state = g_new0 (DeepCountState, 1);
2901 	state->directory = directory;
2902 	state->cancellable = g_cancellable_new ();
2903 	state->seen_deep_count_inodes = g_array_new (FALSE, TRUE, sizeof (guint64));
2904 
2905 	directory->details->deep_count_in_progress = state;
2906 
2907 	location = nemo_file_get_location (file);
2908 	state->fs_id = NULL;
2909 	g_file_query_info_async (location,
2910 				 G_FILE_ATTRIBUTE_ID_FILESYSTEM,
2911 				 G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
2912 				 G_PRIORITY_DEFAULT,
2913 				 NULL,
2914 				 deep_count_got_info,
2915 				 state);
2916 	g_object_unref (location);
2917 }
2918 
2919 static void
mime_list_stop(NemoDirectory * directory)2920 mime_list_stop (NemoDirectory *directory)
2921 {
2922 	NemoFile *file;
2923 
2924 	if (directory->details->mime_list_in_progress != NULL) {
2925 		file = directory->details->mime_list_in_progress->mime_list_file;
2926 		if (file != NULL) {
2927 			g_assert (NEMO_IS_FILE (file));
2928 			g_assert (file->details->directory == directory);
2929 			if (is_needy (file,
2930 				      should_get_mime_list,
2931 				      REQUEST_MIME_LIST)) {
2932 				return;
2933 			}
2934 		}
2935 
2936 		/* The count is not wanted, so stop it. */
2937 		mime_list_cancel (directory);
2938 	}
2939 }
2940 
2941 static void
mime_list_state_free(MimeListState * state)2942 mime_list_state_free (MimeListState *state)
2943 {
2944 	if (state->enumerator) {
2945 		if (!g_file_enumerator_is_closed (state->enumerator)) {
2946 			g_file_enumerator_close_async (state->enumerator,
2947 						       0, NULL, NULL, NULL);
2948 		}
2949 		g_object_unref (state->enumerator);
2950 	}
2951 	g_object_unref (state->cancellable);
2952 	istr_set_destroy (state->mime_list_hash);
2953 	nemo_directory_unref (state->directory);
2954 	g_free (state);
2955 }
2956 
2957 
2958 static void
mime_list_done(MimeListState * state,gboolean success)2959 mime_list_done (MimeListState *state, gboolean success)
2960 {
2961 	NemoFile *file;
2962 	NemoDirectory *directory;
2963 
2964 	directory = state->directory;
2965 	g_assert (directory != NULL);
2966 
2967 	file = state->mime_list_file;
2968 
2969 	file->details->mime_list_is_up_to_date = TRUE;
2970 	g_list_free_full (file->details->mime_list, g_free);
2971 	if (success) {
2972 		file->details->mime_list_failed = TRUE;
2973 		file->details->mime_list = NULL;
2974 	} else {
2975 		file->details->got_mime_list = TRUE;
2976 		file->details->mime_list = istr_set_get_as_list	(state->mime_list_hash);
2977 	}
2978 	directory->details->mime_list_in_progress = NULL;
2979 
2980 	/* Send file-changed even if getting the item type list
2981 	 * failed, so interested parties can distinguish between
2982 	 * unknowable and not-yet-known cases.
2983 	 */
2984 	nemo_file_changed (file);
2985 
2986 	/* Start up the next one. */
2987 	async_job_end (directory, "MIME list");
2988 	nemo_directory_async_state_changed (directory);
2989 }
2990 
2991 static void
mime_list_one(MimeListState * state,GFileInfo * info)2992 mime_list_one (MimeListState *state,
2993 	       GFileInfo *info)
2994 {
2995 	const char *mime_type;
2996 
2997 	if (should_skip_file (NULL, info)) {
2998 		g_object_unref (info);
2999 		return;
3000 	}
3001 
3002 	mime_type = g_file_info_get_content_type (info);
3003 	if (mime_type != NULL) {
3004 		istr_set_insert (state->mime_list_hash, mime_type);
3005 	}
3006 }
3007 
3008 static void
mime_list_callback(GObject * source_object,GAsyncResult * res,gpointer user_data)3009 mime_list_callback (GObject *source_object,
3010 		    GAsyncResult *res,
3011 		    gpointer user_data)
3012 {
3013 	MimeListState *state;
3014 	NemoDirectory *directory;
3015 	GError *error;
3016 	GList *files, *l;
3017 	GFileInfo *info;
3018 
3019 	state = user_data;
3020 	directory = state->directory;
3021 
3022 	if (g_cancellable_is_cancelled (state->cancellable)) {
3023 		/* Operation was cancelled. Bail out */
3024 		directory->details->mime_list_in_progress = NULL;
3025 
3026 		async_job_end (directory, "MIME list");
3027 		nemo_directory_async_state_changed (directory);
3028 
3029 		mime_list_state_free (state);
3030 
3031 		return;
3032 	}
3033 
3034 	g_assert (directory->details->mime_list_in_progress != NULL);
3035 	g_assert (directory->details->mime_list_in_progress == state);
3036 
3037 	error = NULL;
3038 	files = g_file_enumerator_next_files_finish (state->enumerator,
3039 						     res, &error);
3040 
3041 	for (l = files; l != NULL; l = l->next) {
3042 		info = l->data;
3043 		mime_list_one (state, info);
3044 		g_object_unref (info);
3045 	}
3046 
3047 	if (files == NULL) {
3048 		mime_list_done (state, error != NULL);
3049 		mime_list_state_free (state);
3050 	} else {
3051 		g_file_enumerator_next_files_async (state->enumerator,
3052 						    DIRECTORY_LOAD_ITEMS_PER_CALLBACK,
3053 						    G_PRIORITY_DEFAULT,
3054 						    state->cancellable,
3055 						    mime_list_callback,
3056 						    state);
3057 	}
3058 
3059 	g_list_free (files);
3060 
3061 	if (error) {
3062 		g_error_free (error);
3063 	}
3064 }
3065 
3066 static void
list_mime_enum_callback(GObject * source_object,GAsyncResult * res,gpointer user_data)3067 list_mime_enum_callback (GObject *source_object,
3068 			 GAsyncResult *res,
3069 			 gpointer user_data)
3070 {
3071 	MimeListState *state;
3072 	GFileEnumerator *enumerator;
3073 	NemoDirectory *directory;
3074 	GError *error;
3075 
3076 	state = user_data;
3077 
3078 	if (g_cancellable_is_cancelled (state->cancellable)) {
3079 		/* Operation was cancelled. Bail out */
3080 		directory = state->directory;
3081 		directory->details->mime_list_in_progress = NULL;
3082 
3083 		async_job_end (directory, "MIME list");
3084 		nemo_directory_async_state_changed (directory);
3085 
3086 		mime_list_state_free (state);
3087 
3088 		return;
3089 	}
3090 
3091 	error = NULL;
3092 	enumerator = g_file_enumerate_children_finish  (G_FILE (source_object),
3093 							res, &error);
3094 
3095 	if (enumerator == NULL) {
3096 		mime_list_done (state, FALSE);
3097 		g_error_free (error);
3098 		mime_list_state_free (state);
3099 		return;
3100 	} else {
3101 		state->enumerator = enumerator;
3102 		g_file_enumerator_next_files_async (state->enumerator,
3103 						    DIRECTORY_LOAD_ITEMS_PER_CALLBACK,
3104 						    G_PRIORITY_DEFAULT,
3105 						    state->cancellable,
3106 						    mime_list_callback,
3107 						    state);
3108 	}
3109 }
3110 
3111 static void
mime_list_start(NemoDirectory * directory,NemoFile * file,gboolean * doing_io)3112 mime_list_start (NemoDirectory *directory,
3113 		 NemoFile *file,
3114 		 gboolean *doing_io)
3115 {
3116 	MimeListState *state;
3117 	GFile *location;
3118 
3119 	mime_list_stop (directory);
3120 
3121 	if (directory->details->mime_list_in_progress != NULL) {
3122 		*doing_io = TRUE;
3123 		return;
3124 	}
3125 
3126 	/* Figure out which file to get a mime list for. */
3127 	if (!is_needy (file,
3128 		       should_get_mime_list,
3129 		       REQUEST_MIME_LIST)) {
3130 		return;
3131 	}
3132 	*doing_io = TRUE;
3133 
3134 	if (!nemo_file_is_directory (file)) {
3135 		g_list_free (file->details->mime_list);
3136 		file->details->mime_list_failed = FALSE;
3137 		file->details->got_mime_list = FALSE;
3138 		file->details->mime_list_is_up_to_date = TRUE;
3139 
3140 		nemo_directory_async_state_changed (directory);
3141 		return;
3142 	}
3143 
3144 	if (!async_job_start (directory, "MIME list")) {
3145 		return;
3146 	}
3147 
3148 
3149 	state = g_new0 (MimeListState, 1);
3150 	state->mime_list_file = file;
3151 	state->directory = nemo_directory_ref (directory);
3152 	state->cancellable = g_cancellable_new ();
3153 	state->mime_list_hash = istr_set_new ();
3154 
3155 	directory->details->mime_list_in_progress = state;
3156 
3157 	location = nemo_file_get_location (file);
3158 #ifdef DEBUG_LOAD_DIRECTORY
3159 	{
3160 		char *uri;
3161 		uri = g_file_get_uri (location);
3162 		g_message ("load_directory called to get MIME list of %s", uri);
3163 		g_free (uri);
3164 	}
3165 #endif
3166 
3167 	g_file_enumerate_children_async (location,
3168 					 G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE,
3169 					 0, /* flags */
3170 					 G_PRIORITY_LOW, /* prio */
3171 					 state->cancellable,
3172 					 list_mime_enum_callback,
3173 					 state);
3174 	g_object_unref (location);
3175 }
3176 
3177 static void
get_info_state_free(GetInfoState * state)3178 get_info_state_free (GetInfoState *state)
3179 {
3180 	g_object_unref (state->cancellable);
3181 	g_free (state);
3182 }
3183 
3184 static void
query_info_callback(GObject * source_object,GAsyncResult * res,gpointer user_data)3185 query_info_callback (GObject *source_object,
3186 		     GAsyncResult *res,
3187 		     gpointer user_data)
3188 {
3189 	NemoDirectory *directory;
3190 	NemoFile *get_info_file;
3191 	GFileInfo *info;
3192 	GetInfoState *state;
3193 	GError *error;
3194 
3195 	state = user_data;
3196 
3197 	if (state->directory == NULL) {
3198 		/* Operation was cancelled. Bail out */
3199 		get_info_state_free (state);
3200 		return;
3201 	}
3202 
3203 	directory = nemo_directory_ref (state->directory);
3204 
3205 	get_info_file = directory->details->get_info_file;
3206 	g_assert (NEMO_IS_FILE (get_info_file));
3207 
3208 	directory->details->get_info_file = NULL;
3209 	directory->details->get_info_in_progress = NULL;
3210 
3211 	/* ref here because we might be removing the last ref when we
3212 	 * mark the file gone below, but we need to keep a ref at
3213 	 * least long enough to send the change notification.
3214 	 */
3215 	nemo_file_ref (get_info_file);
3216 
3217 	error = NULL;
3218 	info = g_file_query_info_finish (G_FILE (source_object), res, &error);
3219 
3220 	if (info == NULL) {
3221 		if (error->domain == G_IO_ERROR && error->code == G_IO_ERROR_NOT_FOUND) {
3222 			/* mark file as gone */
3223 			nemo_file_mark_gone (get_info_file);
3224 		}
3225 		get_info_file->details->file_info_is_up_to_date = TRUE;
3226 		nemo_file_clear_info (get_info_file);
3227 		get_info_file->details->get_info_failed = TRUE;
3228 		get_info_file->details->get_info_error = error;
3229 	} else {
3230 		nemo_file_update_info (get_info_file, info);
3231 		g_object_unref (info);
3232 	}
3233 
3234 	nemo_file_changed (get_info_file);
3235 	nemo_file_unref (get_info_file);
3236 
3237 	async_job_end (directory, "file info");
3238 	nemo_directory_async_state_changed (directory);
3239 
3240 	nemo_directory_unref (directory);
3241 
3242 	get_info_state_free (state);
3243 }
3244 
3245 static void
file_info_stop(NemoDirectory * directory)3246 file_info_stop (NemoDirectory *directory)
3247 {
3248 	NemoFile *file;
3249 
3250 	if (directory->details->get_info_in_progress != NULL) {
3251 		file = directory->details->get_info_file;
3252 		if (file != NULL) {
3253 			g_assert (NEMO_IS_FILE (file));
3254 			g_assert (file->details->directory == directory);
3255 			if (is_needy (file, lacks_info, REQUEST_FILE_INFO)) {
3256 				return;
3257 			}
3258 		}
3259 
3260 		/* The info is not wanted, so stop it. */
3261 		file_info_cancel (directory);
3262 	}
3263 }
3264 
3265 static void
file_info_start(NemoDirectory * directory,NemoFile * file,gboolean * doing_io)3266 file_info_start (NemoDirectory *directory,
3267 		 NemoFile *file,
3268 		 gboolean *doing_io)
3269 {
3270 	GFile *location;
3271 	GetInfoState *state;
3272 
3273 	file_info_stop (directory);
3274 
3275 	if (directory->details->get_info_in_progress != NULL) {
3276 		*doing_io = TRUE;
3277 		return;
3278 	}
3279 
3280 	if (!is_needy (file, lacks_info, REQUEST_FILE_INFO)) {
3281 		return;
3282 	}
3283 	*doing_io = TRUE;
3284 
3285 	if (!async_job_start (directory, "file info")) {
3286 		return;
3287 	}
3288 
3289 	directory->details->get_info_file = file;
3290 	file->details->get_info_failed = FALSE;
3291 	if (file->details->get_info_error) {
3292 		g_error_free (file->details->get_info_error);
3293 		file->details->get_info_error = NULL;
3294 	}
3295 
3296 	state = g_new (GetInfoState, 1);
3297 	state->directory = directory;
3298 	state->cancellable = g_cancellable_new ();
3299 
3300 	directory->details->get_info_in_progress = state;
3301 
3302 	location = nemo_file_get_location (file);
3303 	g_file_query_info_async (location,
3304 				 NEMO_FILE_DEFAULT_ATTRIBUTES,
3305 				 0,
3306 				 G_PRIORITY_DEFAULT,
3307 				 state->cancellable, query_info_callback, state);
3308 	g_object_unref (location);
3309 }
3310 
3311 static void
get_btime_state_free(GetBTimeState * state)3312 get_btime_state_free (GetBTimeState *state)
3313 {
3314     g_object_unref (state->cancellable);
3315     g_free (state);
3316 }
3317 
3318 static void
query_btime_callback(GObject * source_object,GAsyncResult * res,gpointer user_data)3319 query_btime_callback (GObject *source_object,
3320                       GAsyncResult *res,
3321                       gpointer user_data)
3322 {
3323     NemoDirectory *directory;
3324     NemoFile *get_btime_file;
3325     GetBTimeState *state;
3326     GError *error;
3327     time_t btime;
3328 
3329     state = user_data;
3330 
3331     if (state->directory == NULL) {
3332         /* Operation was cancelled. Bail out */
3333         get_btime_state_free (state);
3334         return;
3335     }
3336 
3337     directory = nemo_directory_ref (state->directory);
3338 
3339     get_btime_file = directory->details->get_btime_file;
3340     g_assert (NEMO_IS_FILE (get_btime_file));
3341 
3342     directory->details->get_btime_file = NULL;
3343     directory->details->get_btime_in_progress = NULL;
3344 
3345     /* ref here because we might be removing the last ref when we
3346      * mark the file gone below, but we need to keep a ref at
3347      * least long enough to send the change notification.
3348      */
3349     nemo_file_ref (get_btime_file);
3350 
3351     error = NULL;
3352     btime = nemo_query_btime_finish (G_FILE (source_object), res, &error);
3353 
3354     if (btime == -1) {
3355         get_btime_file->details->btime_is_up_to_date = TRUE;
3356         get_btime_file->details->get_btime_failed = TRUE;
3357         if (error) {
3358             g_clear_error (&error);
3359         }
3360     } else {
3361         get_btime_file->details->btime = btime;
3362         get_btime_file->details->btime_is_up_to_date = TRUE;
3363         get_btime_file->details->get_btime_failed = FALSE;
3364     }
3365 
3366     nemo_file_changed (get_btime_file);
3367     nemo_file_unref (get_btime_file);
3368 
3369     async_job_end (directory, "get btime");
3370     nemo_directory_async_state_changed (directory);
3371 
3372     nemo_directory_unref (directory);
3373 
3374     get_btime_state_free (state);
3375 }
3376 
3377 static void
btime_stop(NemoDirectory * directory)3378 btime_stop (NemoDirectory *directory)
3379 {
3380     NemoFile *file;
3381 
3382     if (directory->details->get_btime_in_progress != NULL) {
3383         file = directory->details->get_btime_file;
3384         if (file != NULL) {
3385             g_assert (NEMO_IS_FILE (file));
3386             g_assert (file->details->directory == directory);
3387             if (is_needy (file, lacks_btime, REQUEST_BTIME)) {
3388                 return;
3389             }
3390         }
3391 
3392         /* The info is not wanted, so stop it. */
3393         btime_cancel (directory);
3394     }
3395 }
3396 
3397 static void
btime_start(NemoDirectory * directory,NemoFile * file,gboolean * doing_io)3398 btime_start (NemoDirectory *directory,
3399          NemoFile *file,
3400          gboolean *doing_io)
3401 {
3402     GFile *location;
3403     GetBTimeState *state;
3404 
3405     btime_stop (directory);
3406 
3407     if (directory->details->get_btime_in_progress != NULL) {
3408         *doing_io = TRUE;
3409         return;
3410     }
3411 
3412     if (!is_needy (file, lacks_btime, REQUEST_BTIME)) {
3413         return;
3414     }
3415     *doing_io = TRUE;
3416 
3417     if (!async_job_start (directory, "get btime")) {
3418         return;
3419     }
3420 
3421     directory->details->get_btime_file = file;
3422     file->details->get_btime_failed = FALSE;
3423 
3424     state = g_new (GetBTimeState, 1);
3425     state->directory = directory;
3426     state->cancellable = g_cancellable_new ();
3427 
3428     directory->details->get_btime_in_progress = state;
3429 
3430     location = nemo_file_get_location (file);
3431     nemo_query_btime_async (location,
3432                             state->cancellable,
3433                             query_btime_callback,
3434                             state);
3435     g_object_unref (location);
3436 }
3437 
3438 static gboolean
favorite_check_callback(GObject * source_object,GAsyncResult * res,gpointer user_data)3439 favorite_check_callback (GObject *source_object,
3440                          GAsyncResult *res,
3441                          gpointer user_data)
3442 {
3443     NemoDirectory *directory;
3444     NemoFile *favorite_check_file;
3445     FavoriteCheckState *state;
3446 
3447     state = user_data;
3448 
3449     if (state->directory == NULL) {
3450         /* Operation was cancelled. Bail out */
3451         g_free (state);
3452         return G_SOURCE_REMOVE;
3453     }
3454 
3455     directory = nemo_directory_ref (state->directory);
3456 
3457     favorite_check_file = directory->details->favorite_check_file;
3458     g_assert (NEMO_IS_FILE (favorite_check_file));
3459 
3460     directory->details->favorite_check_idle_id = 0;
3461     directory->details->favorite_check_file = NULL;
3462     directory->details->favorite_check_in_progress = NULL;
3463 
3464     /* ref here because we might be removing the last ref when we
3465      * mark the file gone below, but we need to keep a ref at
3466      * least long enough to send the change notification.
3467      */
3468     nemo_file_ref (favorite_check_file);
3469 
3470     gchar *uri;
3471     gboolean is_favorite;
3472 
3473     uri = nemo_file_get_uri (favorite_check_file);
3474     is_favorite = xapp_favorites_find_by_uri (xapp_favorites_get_default (), uri) != NULL;
3475 
3476     favorite_check_file->details->favorite_checked = TRUE;
3477 
3478     if (!nemo_file_is_in_favorites (favorite_check_file) &&
3479         is_favorite != nemo_file_get_is_favorite (favorite_check_file)) {
3480         nemo_file_set_is_favorite (favorite_check_file, is_favorite);
3481         nemo_file_changed (favorite_check_file);
3482     }
3483 
3484     g_free (uri);
3485     nemo_file_unref (favorite_check_file);
3486 
3487     async_job_end (directory, "favorite check");
3488     nemo_directory_async_state_changed (directory);
3489 
3490     nemo_directory_unref (directory);
3491 
3492     g_free (state);
3493 
3494     return G_SOURCE_REMOVE;
3495 }
3496 
3497 static void
favorite_check_stop(NemoDirectory * directory)3498 favorite_check_stop (NemoDirectory *directory)
3499 {
3500     NemoFile *file;
3501 
3502     if (directory->details->favorite_check_in_progress != NULL) {
3503         file = directory->details->favorite_check_file;
3504         if (file != NULL) {
3505             g_assert (NEMO_IS_FILE (file));
3506             g_assert (file->details->directory == directory);
3507             if (is_needy (file, lacks_favorite_check, REQUEST_FAVORITE_CHECK)) {
3508                 return;
3509             }
3510         }
3511 
3512         /* The info is not wanted, so stop it. */
3513         favorite_check_cancel (directory);
3514     }
3515 }
3516 
3517 static void
favorite_check_start(NemoDirectory * directory,NemoFile * file,gboolean * doing_io)3518 favorite_check_start (NemoDirectory *directory,
3519                       NemoFile *file,
3520                       gboolean *doing_io)
3521 {
3522     FavoriteCheckState *state;
3523     favorite_check_stop (directory);
3524 
3525     if (directory->details->favorite_check_in_progress != NULL) {
3526         *doing_io = TRUE;
3527         return;
3528     }
3529 
3530     if (!is_needy (file, lacks_favorite_check, REQUEST_FAVORITE_CHECK)) {
3531         return;
3532     }
3533 
3534     *doing_io = TRUE;
3535 
3536     if (!async_job_start (directory, "favorite check")) {
3537         return;
3538     }
3539 
3540     directory->details->favorite_check_file = file;
3541 
3542     state = g_new0 (FavoriteCheckState, 1);
3543     state->directory = directory;
3544 
3545     directory->details->favorite_check_in_progress = state;
3546     directory->details->favorite_check_idle_id = g_idle_add ((GSourceFunc) favorite_check_callback, state);
3547 }
3548 
3549 static gboolean
is_link_trusted(NemoFile * file,gboolean is_launcher)3550 is_link_trusted (NemoFile *file,
3551 		 gboolean is_launcher)
3552 {
3553 	GFile *location;
3554 	gboolean res;
3555 
3556 	if (!is_launcher) {
3557 		return TRUE;
3558 	}
3559 
3560 	if (nemo_file_can_execute (file)) {
3561 		return TRUE;
3562 	}
3563 
3564 	res = FALSE;
3565 
3566 	if (nemo_file_is_local (file)) {
3567 		location = nemo_file_get_location (file);
3568 		res = nemo_is_in_system_dir (location);
3569 		g_object_unref (location);
3570 	}
3571 
3572 	return res;
3573 }
3574 
3575 static void
link_info_done(NemoDirectory * directory,NemoFile * file,const char * uri,const char * name,GIcon * icon,gboolean is_launcher,gboolean is_foreign)3576 link_info_done (NemoDirectory *directory,
3577 		NemoFile *file,
3578 		const char *uri,
3579 		const char *name,
3580 		GIcon *icon,
3581 		gboolean is_launcher,
3582 		gboolean is_foreign)
3583 {
3584 	gboolean is_trusted;
3585 
3586 	file->details->link_info_is_up_to_date = TRUE;
3587 
3588 	is_trusted = is_link_trusted (file, is_launcher);
3589 
3590 	if (is_trusted) {
3591 		nemo_file_set_display_name (file, name, name, TRUE);
3592 	} else {
3593 		nemo_file_set_display_name (file, NULL, NULL, TRUE);
3594 	}
3595 
3596 	file->details->got_link_info = TRUE;
3597 	g_clear_object (&file->details->custom_icon);
3598 
3599 	if (uri) {
3600 		g_free (file->details->activation_uri);
3601 		file->details->activation_uri = NULL;
3602 		file->details->got_custom_activation_uri = TRUE;
3603 		file->details->activation_uri = g_strdup (uri);
3604 	}
3605 	if (is_trusted && (icon != NULL)) {
3606 		file->details->custom_icon = g_object_ref (icon);
3607 	}
3608 	file->details->is_launcher = is_launcher;
3609 	file->details->is_foreign_link = is_foreign;
3610 	file->details->is_trusted_link = is_trusted;
3611 
3612 	nemo_directory_async_state_changed (directory);
3613 }
3614 
3615 static void
link_info_stop(NemoDirectory * directory)3616 link_info_stop (NemoDirectory *directory)
3617 {
3618 	NemoFile *file;
3619 
3620 	if (directory->details->link_info_read_state != NULL) {
3621 		file = directory->details->link_info_read_state->file;
3622 
3623 		if (file != NULL) {
3624 			g_assert (NEMO_IS_FILE (file));
3625 			g_assert (file->details->directory == directory);
3626 			if (is_needy (file,
3627 				      lacks_link_info,
3628 				      REQUEST_LINK_INFO)) {
3629 				return;
3630 			}
3631 		}
3632 
3633 		/* The link info is not wanted, so stop it. */
3634 		link_info_cancel (directory);
3635 	}
3636 }
3637 
3638 static void
link_info_got_data(NemoDirectory * directory,NemoFile * file,gboolean result,goffset bytes_read,char * file_contents)3639 link_info_got_data (NemoDirectory *directory,
3640 		    NemoFile *file,
3641 		    gboolean result,
3642 		    goffset bytes_read,
3643 		    char *file_contents)
3644 {
3645 	char *link_uri, *uri, *name;
3646 	GIcon *icon;
3647 	gboolean is_launcher;
3648 	gboolean is_foreign;
3649 
3650 	nemo_directory_ref (directory);
3651 
3652 	uri = NULL;
3653 	name = NULL;
3654 	icon = NULL;
3655 	is_launcher = FALSE;
3656 	is_foreign = FALSE;
3657 
3658 	/* Handle the case where we read the Nemo link. */
3659 	if (result) {
3660 		link_uri = nemo_file_get_uri (file);
3661 		nemo_link_get_link_info_given_file_contents (file_contents, bytes_read, link_uri,
3662 								 &uri, &name, &icon, &is_launcher, &is_foreign);
3663 		g_free (link_uri);
3664 	} else {
3665 		/* FIXME bugzilla.gnome.org 42433: We should report this error to the user. */
3666 	}
3667 
3668 	nemo_file_ref (file);
3669 	link_info_done (directory, file, uri, name, icon, is_launcher, is_foreign);
3670 	nemo_file_changed (file);
3671 	nemo_file_unref (file);
3672 
3673 	g_free (uri);
3674 	g_free (name);
3675 
3676 	if (icon != NULL) {
3677 		g_object_unref (icon);
3678 	}
3679 
3680 	nemo_directory_unref (directory);
3681 }
3682 
3683 static void
link_info_read_state_free(LinkInfoReadState * state)3684 link_info_read_state_free (LinkInfoReadState *state)
3685 {
3686 	g_object_unref (state->cancellable);
3687 	g_free (state);
3688 }
3689 
3690 static void
link_info_nemo_link_read_callback(GObject * source_object,GAsyncResult * res,gpointer user_data)3691 link_info_nemo_link_read_callback (GObject *source_object,
3692 				       GAsyncResult *res,
3693 				       gpointer user_data)
3694 {
3695 	LinkInfoReadState *state;
3696 	gsize file_size;
3697 	char *file_contents;
3698 	gboolean result;
3699 	NemoDirectory *directory;
3700 
3701 	state = user_data;
3702 
3703 	if (state->directory == NULL) {
3704 		/* Operation was cancelled. Bail out */
3705 		link_info_read_state_free (state);
3706 		return;
3707 	}
3708 
3709 	directory = nemo_directory_ref (state->directory);
3710 
3711 	result = g_file_load_contents_finish (G_FILE (source_object),
3712 					      res,
3713 					      &file_contents, &file_size,
3714 					      NULL, NULL);
3715 
3716 	state->directory->details->link_info_read_state = NULL;
3717 	async_job_end (state->directory, "link info");
3718 
3719 	link_info_got_data (state->directory, state->file, result, file_size, file_contents);
3720 
3721 	if (result) {
3722 		g_free (file_contents);
3723 	}
3724 
3725 	link_info_read_state_free (state);
3726 
3727 	nemo_directory_unref (directory);
3728 }
3729 
3730 static void
link_info_start(NemoDirectory * directory,NemoFile * file,gboolean * doing_io)3731 link_info_start (NemoDirectory *directory,
3732 		 NemoFile *file,
3733 		 gboolean *doing_io)
3734 {
3735 	GFile *location;
3736 	gboolean nemo_style_link;
3737 	LinkInfoReadState *state;
3738 
3739 	if (directory->details->link_info_read_state != NULL) {
3740 		*doing_io = TRUE;
3741 		return;
3742 	}
3743 
3744 	if (!is_needy (file,
3745 		       lacks_link_info,
3746 		       REQUEST_LINK_INFO)) {
3747 		return;
3748 	}
3749 	*doing_io = TRUE;
3750 
3751 	/* Figure out if it is a link. */
3752 	nemo_style_link = nemo_file_is_nemo_link (file);
3753 	location = nemo_file_get_location (file);
3754 
3755 	/* If it's not a link we are done. If it is, we need to read it. */
3756 	if (!nemo_style_link) {
3757 		link_info_done (directory, file, NULL, NULL, NULL, FALSE, FALSE);
3758 	} else {
3759 		if (!async_job_start (directory, "link info")) {
3760 			g_object_unref (location);
3761 			return;
3762 		}
3763 
3764 		state = g_new0 (LinkInfoReadState, 1);
3765 		state->directory = directory;
3766 		state->file = file;
3767 		state->cancellable = g_cancellable_new ();
3768 
3769 		directory->details->link_info_read_state = state;
3770 
3771 		g_file_load_contents_async (location,
3772 					    state->cancellable,
3773 					    link_info_nemo_link_read_callback,
3774 					    state);
3775 	}
3776 	g_object_unref (location);
3777 }
3778 
3779 static void
thumbnail_done(NemoDirectory * directory,NemoFile * file,GdkPixbuf * pixbuf,gboolean tried_original)3780 thumbnail_done (NemoDirectory *directory,
3781 		NemoFile *file,
3782 		GdkPixbuf *pixbuf,
3783 		gboolean tried_original)
3784 {
3785 	const char *thumb_mtime_str;
3786 	time_t thumb_mtime = 0;
3787 
3788 	file->details->thumbnail_is_up_to_date = TRUE;
3789 	file->details->thumbnail_tried_original  = tried_original;
3790 	if (file->details->thumbnail) {
3791 		g_object_unref (file->details->thumbnail);
3792 		file->details->thumbnail = NULL;
3793 	}
3794 
3795 	if (pixbuf) {
3796 		if (tried_original) {
3797 			thumb_mtime = file->details->mtime;
3798 		} else {
3799 			thumb_mtime_str = gdk_pixbuf_get_option (pixbuf, "tEXt::Thumb::MTime");
3800 			if (thumb_mtime_str) {
3801 				thumb_mtime = atol (thumb_mtime_str);
3802 			}
3803 		}
3804 
3805 		if (thumb_mtime == 0 ||
3806 		    thumb_mtime == file->details->mtime) {
3807 			file->details->thumbnail = g_object_ref (pixbuf);
3808 			file->details->thumbnail_mtime = thumb_mtime;
3809             file->details->thumbnail_throttle_count = 1;
3810 		} else {
3811 			g_free (file->details->thumbnail_path);
3812             g_object_unref (pixbuf);
3813 			file->details->thumbnail_path = NULL;
3814 		}
3815 
3816 	}
3817 
3818 	nemo_directory_async_state_changed (directory);
3819 }
3820 
3821 static void
thumbnail_stop(NemoDirectory * directory)3822 thumbnail_stop (NemoDirectory *directory)
3823 {
3824 	NemoFile *file;
3825 
3826 	if (directory->details->thumbnail_state != NULL) {
3827 		file = directory->details->thumbnail_state->file;
3828 
3829 		if (file != NULL) {
3830 			g_assert (NEMO_IS_FILE (file));
3831 			g_assert (file->details->directory == directory);
3832 			if (is_needy (file,
3833 				      lacks_thumbnail,
3834 				      REQUEST_THUMBNAIL)) {
3835 				return;
3836 			}
3837 		}
3838 
3839 		/* The link info is not wanted, so stop it. */
3840 		thumbnail_cancel (directory);
3841 	}
3842 }
3843 
3844 static void
thumbnail_got_pixbuf(NemoDirectory * directory,NemoFile * file,GdkPixbuf * pixbuf,gboolean tried_original)3845 thumbnail_got_pixbuf (NemoDirectory *directory,
3846 		      NemoFile *file,
3847 		      GdkPixbuf *pixbuf,
3848 		      gboolean tried_original)
3849 {
3850 	nemo_directory_ref (directory);
3851 
3852 	nemo_file_ref (file);
3853 	thumbnail_done (directory, file, pixbuf, tried_original);
3854 	nemo_file_changed (file);
3855 	nemo_file_unref (file);
3856 
3857 	if (pixbuf) {
3858 		g_object_unref (pixbuf);
3859 	}
3860 
3861 	nemo_directory_unref (directory);
3862 }
3863 
3864 static void
thumbnail_state_free(ThumbnailState * state)3865 thumbnail_state_free (ThumbnailState *state)
3866 {
3867 	g_object_unref (state->cancellable);
3868 	g_free (state);
3869 }
3870 
3871 extern int cached_thumbnail_size;
3872 
3873 /* scale very large images down to the max. size we need */
3874 static void
thumbnail_loader_size_prepared(GdkPixbufLoader * loader,int width,int height,gpointer user_data)3875 thumbnail_loader_size_prepared (GdkPixbufLoader *loader,
3876 				int width,
3877 				int height,
3878 				gpointer user_data)
3879 {
3880 	int max_thumbnail_size;
3881 	double aspect_ratio;
3882 
3883 	aspect_ratio = ((double) width) / height;
3884 
3885 	/* cf. nemo_file_get_icon() */
3886 	max_thumbnail_size = NEMO_ICON_SIZE_LARGEST * cached_thumbnail_size / NEMO_ICON_SIZE_STANDARD;
3887 	if (MAX (width, height) > max_thumbnail_size) {
3888 		if (width > height) {
3889 			width = max_thumbnail_size;
3890 			height = width / aspect_ratio;
3891 		} else {
3892 			height = max_thumbnail_size;
3893 			width = height * aspect_ratio;
3894 		}
3895 
3896 		gdk_pixbuf_loader_set_size (loader, width, height);
3897 	}
3898 }
3899 
3900 static GdkPixbuf *
get_pixbuf_for_content(goffset file_len,char * file_contents)3901 get_pixbuf_for_content (goffset file_len,
3902 			char *file_contents)
3903 {
3904 	gboolean res;
3905 	GdkPixbuf *pixbuf, *pixbuf2;
3906 	GdkPixbufLoader *loader;
3907 	gsize chunk_len;
3908 	pixbuf = NULL;
3909 
3910 	loader = gdk_pixbuf_loader_new ();
3911 	g_signal_connect (loader, "size-prepared",
3912 			  G_CALLBACK (thumbnail_loader_size_prepared),
3913 			  NULL);
3914 
3915 	/* For some reason we have to write in chunks, or gdk-pixbuf fails */
3916 	res = TRUE;
3917 	while (res && file_len > 0) {
3918 		chunk_len = file_len;
3919 		res = gdk_pixbuf_loader_write (loader, (guchar *) file_contents, chunk_len, NULL);
3920 		file_contents += chunk_len;
3921 		file_len -= chunk_len;
3922 	}
3923 	if (res) {
3924 		res = gdk_pixbuf_loader_close (loader, NULL);
3925 	}
3926 	if (res) {
3927 		pixbuf = g_object_ref (gdk_pixbuf_loader_get_pixbuf (loader));
3928 	}
3929 	g_object_unref (G_OBJECT (loader));
3930 
3931 	if (pixbuf) {
3932 		pixbuf2 = gdk_pixbuf_apply_embedded_orientation (pixbuf);
3933 		g_object_unref (pixbuf);
3934 		pixbuf = pixbuf2;
3935 	}
3936 	return pixbuf;
3937 }
3938 
3939 
3940 static void
thumbnail_read_callback(GObject * source_object,GAsyncResult * res,gpointer user_data)3941 thumbnail_read_callback (GObject *source_object,
3942 			 GAsyncResult *res,
3943 			 gpointer user_data)
3944 {
3945 	ThumbnailState *state;
3946 	gsize file_size;
3947 	char *file_contents;
3948 	gboolean result;
3949 	NemoDirectory *directory;
3950 	GdkPixbuf *pixbuf;
3951 	GFile *location;
3952 
3953 	state = user_data;
3954 
3955 	if (state->directory == NULL) {
3956 		/* Operation was cancelled. Bail out */
3957 		thumbnail_state_free (state);
3958 		return;
3959 	}
3960 
3961 	directory = nemo_directory_ref (state->directory);
3962 
3963 	result = g_file_load_contents_finish (G_FILE (source_object),
3964 					      res,
3965 					      &file_contents, &file_size,
3966 					      NULL, NULL);
3967 
3968 	pixbuf = NULL;
3969 	if (result) {
3970 		pixbuf = get_pixbuf_for_content (file_size, file_contents);
3971 		g_free (file_contents);
3972 	}
3973 
3974 	if (pixbuf == NULL && state->trying_original) {
3975 		state->trying_original = FALSE;
3976 
3977 		location = g_file_new_for_path (state->file->details->thumbnail_path);
3978 
3979 		g_file_load_contents_async (location,
3980 					    state->cancellable,
3981 					    thumbnail_read_callback,
3982 					    state);
3983 		g_object_unref (location);
3984 	} else {
3985 		state->directory->details->thumbnail_state = NULL;
3986 		async_job_end (state->directory, "thumbnail");
3987 
3988 		thumbnail_got_pixbuf (state->directory, state->file, pixbuf, state->tried_original);
3989 
3990 		thumbnail_state_free (state);
3991 	}
3992 
3993 	nemo_directory_unref (directory);
3994 }
3995 
3996 static void
thumbnail_start(NemoDirectory * directory,NemoFile * file,gboolean * doing_io)3997 thumbnail_start (NemoDirectory *directory,
3998 		 NemoFile *file,
3999 		 gboolean *doing_io)
4000 {
4001 	GFile *location;
4002 	ThumbnailState *state;
4003 
4004 	if (directory->details->thumbnail_state != NULL) {
4005 		*doing_io = TRUE;
4006 		return;
4007 	}
4008 
4009 	if (!is_needy (file,
4010 		       lacks_thumbnail,
4011 		       REQUEST_THUMBNAIL)) {
4012 		return;
4013 	}
4014 	*doing_io = TRUE;
4015 
4016 	if (!async_job_start (directory, "thumbnail")) {
4017 		return;
4018 	}
4019 
4020 	state = g_new0 (ThumbnailState, 1);
4021 	state->directory = directory;
4022 	state->file = file;
4023 	state->cancellable = g_cancellable_new ();
4024 
4025 	if (file->details->thumbnail_wants_original) {
4026 		state->tried_original = TRUE;
4027 		state->trying_original = TRUE;
4028 		location = nemo_file_get_location (file);
4029 	} else {
4030 		location = g_file_new_for_path (file->details->thumbnail_path);
4031 	}
4032 
4033 	directory->details->thumbnail_state = state;
4034 
4035 	g_file_load_contents_async (location,
4036 				    state->cancellable,
4037 				    thumbnail_read_callback,
4038 				    state);
4039 	g_object_unref (location);
4040 }
4041 
4042 static void
mount_stop(NemoDirectory * directory)4043 mount_stop (NemoDirectory *directory)
4044 {
4045 	NemoFile *file;
4046 
4047 	if (directory->details->mount_state != NULL) {
4048 		file = directory->details->mount_state->file;
4049 
4050 		if (file != NULL) {
4051 			g_assert (NEMO_IS_FILE (file));
4052 			g_assert (file->details->directory == directory);
4053 			if (is_needy (file,
4054 				      lacks_mount,
4055 				      REQUEST_MOUNT)) {
4056 				return;
4057 			}
4058 		}
4059 
4060 		/* The link info is not wanted, so stop it. */
4061 		mount_cancel (directory);
4062 	}
4063 }
4064 
4065 static void
mount_state_free(MountState * state)4066 mount_state_free (MountState *state)
4067 {
4068 	g_object_unref (state->cancellable);
4069 	g_free (state);
4070 }
4071 
4072 static void
got_mount(MountState * state,GMount * mount)4073 got_mount (MountState *state, GMount *mount)
4074 {
4075 	NemoDirectory *directory;
4076 	NemoFile *file;
4077 
4078 	directory = nemo_directory_ref (state->directory);
4079 
4080 	state->directory->details->mount_state = NULL;
4081 	async_job_end (state->directory, "mount");
4082 
4083 	file = nemo_file_ref (state->file);
4084 
4085 	file->details->mount_is_up_to_date = TRUE;
4086 	nemo_file_set_mount (file, mount);
4087 
4088 	nemo_directory_async_state_changed (directory);
4089 	nemo_file_changed (file);
4090 
4091 	nemo_file_unref (file);
4092 
4093 	nemo_directory_unref (directory);
4094 
4095 	mount_state_free (state);
4096 
4097 }
4098 
4099 static void
find_enclosing_mount_callback(GObject * source_object,GAsyncResult * res,gpointer user_data)4100 find_enclosing_mount_callback (GObject *source_object,
4101 			       GAsyncResult *res,
4102 			       gpointer user_data)
4103 {
4104 	GMount *mount;
4105 	MountState *state;
4106 	GFile *location, *root;
4107 
4108 	state = user_data;
4109 	if (state->directory == NULL) {
4110 		/* Operation was cancelled. Bail out */
4111 		mount_state_free (state);
4112 		return;
4113 	}
4114 
4115 	mount = g_file_find_enclosing_mount_finish (G_FILE (source_object),
4116 						    res, NULL);
4117 
4118 	if (mount) {
4119 		root = g_mount_get_root (mount);
4120 		location = nemo_file_get_location (state->file);
4121 		if (!g_file_equal (location, root)) {
4122 			g_object_unref (mount);
4123 			mount = NULL;
4124 		}
4125 		g_object_unref (root);
4126 		g_object_unref (location);
4127 	}
4128 
4129 	got_mount (state, mount);
4130 
4131 	if (mount) {
4132 		g_object_unref (mount);
4133 	}
4134 }
4135 
4136 static GMount *
get_mount_at(GFile * target)4137 get_mount_at (GFile *target)
4138 {
4139 	GVolumeMonitor *monitor;
4140 	GFile *root;
4141 	GList *mounts, *l;
4142 	GMount *found;
4143 
4144 	monitor = g_volume_monitor_get ();
4145 	mounts = g_volume_monitor_get_mounts (monitor);
4146 
4147 	found = NULL;
4148 	for (l = mounts; l != NULL; l = l->next) {
4149 		GMount *mount = G_MOUNT (l->data);
4150 
4151 		if (g_mount_is_shadowed (mount))
4152 			continue;
4153 
4154 		root = g_mount_get_root (mount);
4155 
4156 		if (g_file_equal (target, root)) {
4157 			found = g_object_ref (mount);
4158 			break;
4159 		}
4160 
4161 		g_object_unref (root);
4162 	}
4163 
4164 	g_list_free_full (mounts, g_object_unref);
4165 
4166 	g_object_unref (monitor);
4167 
4168 	return found;
4169 }
4170 
4171 static void
mount_start(NemoDirectory * directory,NemoFile * file,gboolean * doing_io)4172 mount_start (NemoDirectory *directory,
4173 	     NemoFile *file,
4174 	     gboolean *doing_io)
4175 {
4176 	GFile *location;
4177 	MountState *state;
4178 
4179 	if (directory->details->mount_state != NULL) {
4180 		*doing_io = TRUE;
4181 		return;
4182 	}
4183 
4184 	if (!is_needy (file,
4185 		       lacks_mount,
4186 		       REQUEST_MOUNT)) {
4187 		return;
4188 	}
4189 	*doing_io = TRUE;
4190 
4191 	if (!async_job_start (directory, "mount")) {
4192 		return;
4193 	}
4194 
4195 	state = g_new0 (MountState, 1);
4196 	state->directory = directory;
4197 	state->file = file;
4198 	state->cancellable = g_cancellable_new ();
4199 
4200 	location = nemo_file_get_location (file);
4201 
4202 	directory->details->mount_state = state;
4203 
4204 	if (file->details->type == G_FILE_TYPE_MOUNTABLE) {
4205 		GFile *target;
4206 		GMount *mount;
4207 
4208 		mount = NULL;
4209 		target = nemo_file_get_activation_location (file);
4210 		if (target != NULL) {
4211 			mount = get_mount_at (target);
4212 			g_object_unref (target);
4213 		}
4214 
4215 		got_mount (state, mount);
4216 
4217 		if (mount) {
4218 			g_object_unref (mount);
4219 		}
4220 	} else {
4221 		g_file_find_enclosing_mount_async (location,
4222 						   G_PRIORITY_DEFAULT,
4223 						   state->cancellable,
4224 						   find_enclosing_mount_callback,
4225 						   state);
4226 	}
4227 	g_object_unref (location);
4228 }
4229 
4230 static void
filesystem_info_cancel(NemoDirectory * directory)4231 filesystem_info_cancel (NemoDirectory *directory)
4232 {
4233 	if (directory->details->filesystem_info_state != NULL) {
4234 		g_cancellable_cancel (directory->details->filesystem_info_state->cancellable);
4235 		directory->details->filesystem_info_state->directory = NULL;
4236 		directory->details->filesystem_info_state = NULL;
4237 		async_job_end (directory, "filesystem info");
4238 	}
4239 }
4240 
4241 static void
filesystem_info_stop(NemoDirectory * directory)4242 filesystem_info_stop (NemoDirectory *directory)
4243 {
4244 	NemoFile *file;
4245 
4246 	if (directory->details->filesystem_info_state != NULL) {
4247 		file = directory->details->filesystem_info_state->file;
4248 
4249 		if (file != NULL) {
4250 			g_assert (NEMO_IS_FILE (file));
4251 			g_assert (file->details->directory == directory);
4252 			if (is_needy (file,
4253 				      lacks_filesystem_info,
4254 				      REQUEST_FILESYSTEM_INFO)) {
4255 				return;
4256 			}
4257 		}
4258 
4259 		/* The filesystem info is not wanted, so stop it. */
4260 		filesystem_info_cancel (directory);
4261 	}
4262 }
4263 
4264 static void
filesystem_info_state_free(FilesystemInfoState * state)4265 filesystem_info_state_free (FilesystemInfoState *state)
4266 {
4267 	g_object_unref (state->cancellable);
4268 	g_free (state);
4269 }
4270 
4271 static void
got_filesystem_info(FilesystemInfoState * state,GFileInfo * info)4272 got_filesystem_info (FilesystemInfoState *state, GFileInfo *info)
4273 {
4274 	NemoDirectory *directory;
4275 	NemoFile *file;
4276 
4277 	/* careful here, info may be NULL */
4278 
4279 	directory = nemo_directory_ref (state->directory);
4280 
4281 	state->directory->details->filesystem_info_state = NULL;
4282 	async_job_end (state->directory, "filesystem info");
4283 
4284 	file = nemo_file_ref (state->file);
4285 
4286 	file->details->filesystem_info_is_up_to_date = TRUE;
4287 	if (info != NULL) {
4288 		file->details->filesystem_use_preview =
4289 			g_file_info_get_attribute_uint32 (info, G_FILE_ATTRIBUTE_FILESYSTEM_USE_PREVIEW);
4290 		file->details->filesystem_readonly =
4291 			g_file_info_get_attribute_boolean (info, G_FILE_ATTRIBUTE_FILESYSTEM_READONLY);
4292 	}
4293 
4294 	nemo_directory_async_state_changed (directory);
4295 	nemo_file_changed (file);
4296 
4297 	nemo_file_unref (file);
4298 
4299 	nemo_directory_unref (directory);
4300 
4301 	filesystem_info_state_free (state);
4302 }
4303 
4304 static void
query_filesystem_info_callback(GObject * source_object,GAsyncResult * res,gpointer user_data)4305 query_filesystem_info_callback (GObject *source_object,
4306 				GAsyncResult *res,
4307 				gpointer user_data)
4308 {
4309 	GFileInfo *info;
4310 	FilesystemInfoState *state;
4311 
4312 	state = user_data;
4313 	if (state->directory == NULL) {
4314 		/* Operation was cancelled. Bail out */
4315 		filesystem_info_state_free (state);
4316 		return;
4317 	}
4318 
4319 	info = g_file_query_filesystem_info_finish (G_FILE (source_object), res, NULL);
4320 
4321 	got_filesystem_info (state, info);
4322 
4323 	if (info != NULL) {
4324 		g_object_unref (info);
4325 	}
4326 }
4327 
4328 static void
filesystem_info_start(NemoDirectory * directory,NemoFile * file,gboolean * doing_io)4329 filesystem_info_start (NemoDirectory *directory,
4330 		       NemoFile *file,
4331 		       gboolean *doing_io)
4332 {
4333 	GFile *location;
4334 	FilesystemInfoState *state;
4335 
4336 	if (directory->details->filesystem_info_state != NULL) {
4337 		*doing_io = TRUE;
4338 		return;
4339 	}
4340 
4341 	if (!is_needy (file,
4342 		       lacks_filesystem_info,
4343 		       REQUEST_FILESYSTEM_INFO)) {
4344 		return;
4345 	}
4346 	*doing_io = TRUE;
4347 
4348 	if (!async_job_start (directory, "filesystem info")) {
4349 		return;
4350 	}
4351 
4352 	state = g_new0 (FilesystemInfoState, 1);
4353 	state->directory = directory;
4354 	state->file = file;
4355 	state->cancellable = g_cancellable_new ();
4356 
4357 	location = nemo_file_get_location (file);
4358 
4359 	directory->details->filesystem_info_state = state;
4360 
4361 	g_file_query_filesystem_info_async (location,
4362 					    G_FILE_ATTRIBUTE_FILESYSTEM_READONLY ","
4363 					    G_FILE_ATTRIBUTE_FILESYSTEM_USE_PREVIEW,
4364 					    G_PRIORITY_DEFAULT,
4365 					    state->cancellable,
4366 					    query_filesystem_info_callback,
4367 					    state);
4368 	g_object_unref (location);
4369 }
4370 
4371 static void
extension_info_cancel(NemoDirectory * directory)4372 extension_info_cancel (NemoDirectory *directory)
4373 {
4374 	if (directory->details->extension_info_in_progress != NULL) {
4375 		if (directory->details->extension_info_idle > 0) {
4376 			g_source_remove (directory->details->extension_info_idle);
4377 			directory->details->extension_info_idle = 0;
4378 		} else {
4379 			nemo_info_provider_cancel_update
4380 				(directory->details->extension_info_provider,
4381 				 directory->details->extension_info_in_progress);
4382             g_closure_invalidate (directory->details->extension_info_closure);
4383 		}
4384 
4385 		directory->details->extension_info_in_progress = NULL;
4386 		directory->details->extension_info_file = NULL;
4387 		directory->details->extension_info_provider = NULL;
4388         g_closure_unref (directory->details->extension_info_closure);
4389         directory->details->extension_info_closure = NULL;
4390 
4391 		async_job_end (directory, "extension info");
4392 	}
4393 }
4394 
4395 static void
extension_info_stop(NemoDirectory * directory)4396 extension_info_stop (NemoDirectory *directory)
4397 {
4398 	if (directory->details->extension_info_in_progress != NULL) {
4399 		NemoFile *file;
4400 
4401 		file = directory->details->extension_info_file;
4402 		if (file != NULL) {
4403 			g_assert (NEMO_IS_FILE (file));
4404 			g_assert (file->details->directory == directory);
4405 			if (is_needy (file, lacks_extension_info, REQUEST_EXTENSION_INFO)) {
4406 				return;
4407 			}
4408 		}
4409 
4410 		/* The info is not wanted, so stop it. */
4411 		extension_info_cancel (directory);
4412 
4413         nemo_directory_unref (directory);
4414 	}
4415 }
4416 
4417 static void
finish_info_provider(NemoDirectory * directory,NemoFile * file,NemoInfoProvider * provider)4418 finish_info_provider (NemoDirectory *directory,
4419 		      NemoFile *file,
4420 		      NemoInfoProvider *provider)
4421 {
4422 	file->details->pending_info_providers =
4423 		g_list_remove  (file->details->pending_info_providers,
4424 				provider);
4425 	g_object_unref (provider);
4426 
4427 	if (file->details->pending_info_providers == NULL) {
4428 		nemo_file_info_providers_done (file);
4429 	}
4430 
4431     nemo_directory_unref (directory);
4432 
4433     nemo_directory_async_state_changed (directory);
4434 }
4435 
4436 
4437 static gboolean
info_provider_idle_callback(gpointer user_data)4438 info_provider_idle_callback (gpointer user_data)
4439 {
4440 	InfoProviderResponse *response;
4441 	NemoDirectory *directory;
4442 
4443 	response = user_data;
4444 	directory = response->directory;
4445 
4446 	if (response->handle != directory->details->extension_info_in_progress
4447 	    || response->provider != directory->details->extension_info_provider) {
4448 		g_warning ("Unexpected plugin response.  This probably indicates a bug in a Nemo extension: handle=%p", response->handle);
4449 	} else {
4450 		NemoFile *file;
4451 		async_job_end (directory, "extension info");
4452 
4453 		file = directory->details->extension_info_file;
4454 
4455 		directory->details->extension_info_file = NULL;
4456 		directory->details->extension_info_provider = NULL;
4457 		directory->details->extension_info_in_progress = NULL;
4458 		directory->details->extension_info_idle = 0;
4459         g_closure_unref (directory->details->extension_info_closure);
4460         directory->details->extension_info_closure = NULL;
4461 
4462 		finish_info_provider (directory, file, response->provider);
4463 	}
4464 
4465 	return FALSE;
4466 }
4467 
4468 static void
info_provider_callback(NemoInfoProvider * provider,NemoOperationHandle * handle,NemoOperationResult result,gpointer user_data)4469 info_provider_callback (NemoInfoProvider *provider,
4470 			NemoOperationHandle *handle,
4471 			NemoOperationResult result,
4472 			gpointer user_data)
4473 {
4474 	InfoProviderResponse *response;
4475 
4476 	response = g_new0 (InfoProviderResponse, 1);
4477 	response->provider = provider;
4478 	response->handle = handle;
4479 	response->result = result;
4480 	response->directory = NEMO_DIRECTORY (user_data);
4481 
4482 	response->directory->details->extension_info_idle =
4483 		g_idle_add_full (G_PRIORITY_DEFAULT_IDLE,
4484 				 info_provider_idle_callback, response,
4485 				 g_free);
4486 }
4487 
4488 static void
extension_info_start(NemoDirectory * directory,NemoFile * file,gboolean * doing_io)4489 extension_info_start (NemoDirectory *directory,
4490 		      NemoFile *file,
4491 		      gboolean *doing_io)
4492 {
4493 	NemoInfoProvider *provider;
4494 	NemoOperationResult result;
4495 	NemoOperationHandle *handle;
4496 	GClosure *update_complete;
4497 
4498 	if (directory->details->extension_info_in_progress != NULL) {
4499 		*doing_io = TRUE;
4500 		return;
4501 	}
4502 
4503 	if (!is_needy (file, lacks_extension_info, REQUEST_EXTENSION_INFO)) {
4504 		return;
4505 	}
4506 	*doing_io = TRUE;
4507 
4508 	if (!async_job_start (directory, "extension info")) {
4509 		return;
4510 	}
4511 
4512 	provider = file->details->pending_info_providers->data;
4513 
4514     /* If the user navigates out of the current directory while this job is
4515      * running, cleanup will occur before a progress-type callback can complete,
4516      * potentially causing a segfault as directory->details->extension_info_could
4517      * be NULL during finish_info_provider. */
4518     nemo_directory_ref (directory);
4519 
4520     handle = NULL;
4521 
4522 	update_complete = g_cclosure_new (G_CALLBACK (info_provider_callback),
4523 					  directory,
4524 					  NULL);
4525 	g_closure_set_marshal (update_complete,
4526 			       g_cclosure_marshal_generic);
4527 
4528 	result = nemo_info_provider_update_file_info
4529 		(provider,
4530 		 NEMO_FILE_INFO (file),
4531 		 update_complete,
4532 		 &handle);
4533 
4534 	if (result == NEMO_OPERATION_COMPLETE ||
4535 	    result == NEMO_OPERATION_FAILED) {
4536         g_closure_unref (update_complete);
4537 
4538 		finish_info_provider (directory, file, provider);
4539 		async_job_end (directory, "extension info");
4540 	} else {
4541 		directory->details->extension_info_in_progress = handle;
4542 		directory->details->extension_info_provider = provider;
4543 		directory->details->extension_info_file = file;
4544         directory->details->extension_info_closure = update_complete;
4545 	}
4546 }
4547 
4548 static void
start_or_stop_io(NemoDirectory * directory)4549 start_or_stop_io (NemoDirectory *directory)
4550 {
4551 	NemoFile *file;
4552 	gboolean doing_io;
4553 
4554 	/* Start or stop reading files. */
4555 	file_list_start_or_stop (directory);
4556 
4557 	/* Stop any no longer wanted attribute fetches. */
4558 	file_info_stop (directory);
4559     btime_stop (directory);
4560 	directory_count_stop (directory);
4561 	deep_count_stop (directory);
4562 	mime_list_stop (directory);
4563 	link_info_stop (directory);
4564 	extension_info_stop (directory);
4565 	mount_stop (directory);
4566 	thumbnail_stop (directory);
4567 	filesystem_info_stop (directory);
4568     favorite_check_stop (directory);
4569 
4570 	doing_io = FALSE;
4571 	/* Take files that are all done off the queue. */
4572 	while (!nemo_file_queue_is_empty (directory->details->high_priority_queue)) {
4573 		file = nemo_file_queue_head (directory->details->high_priority_queue);
4574 
4575 		/* Start getting attributes if possible */
4576 		file_info_start (directory, file, &doing_io);
4577 		link_info_start (directory, file, &doing_io);
4578 
4579 		if (doing_io) {
4580 			return;
4581 		}
4582 
4583 		move_file_to_low_priority_queue (directory, file);
4584 	}
4585 
4586 	/* High priority queue must be empty */
4587 	while (!nemo_file_queue_is_empty (directory->details->low_priority_queue)) {
4588 		file = nemo_file_queue_head (directory->details->low_priority_queue);
4589 
4590 		/* Start getting attributes if possible */
4591         btime_start (directory, file, &doing_io);
4592 		mount_start (directory, file, &doing_io);
4593 		directory_count_start (directory, file, &doing_io);
4594 		deep_count_start (directory, file, &doing_io);
4595 		mime_list_start (directory, file, &doing_io);
4596 		thumbnail_start (directory, file, &doing_io);
4597 		filesystem_info_start (directory, file, &doing_io);
4598         favorite_check_start (directory, file, &doing_io);
4599 
4600 		if (doing_io) {
4601 			return;
4602 		}
4603 
4604 		move_file_to_extension_queue (directory, file);
4605 	}
4606 
4607 	/* Low priority queue must be empty */
4608 	while (!nemo_file_queue_is_empty (directory->details->extension_queue)) {
4609 		file = nemo_file_queue_head (directory->details->extension_queue);
4610 
4611 		/* Start getting attributes if possible */
4612 		extension_info_start (directory, file, &doing_io);
4613 		if (doing_io) {
4614 			return;
4615 		}
4616 
4617 		nemo_directory_remove_file_from_work_queue (directory, file);
4618 	}
4619 }
4620 
4621 /* Call this when the monitor or call when ready list changes,
4622  * or when some I/O is completed.
4623  */
4624 void
nemo_directory_async_state_changed(NemoDirectory * directory)4625 nemo_directory_async_state_changed (NemoDirectory *directory)
4626 {
4627 	/* Check if any callbacks are satisfied and call them if they
4628 	 * are. Do this last so that any changes done in start or stop
4629 	 * I/O functions immediately (not in callbacks) are taken into
4630 	 * consideration. If any callbacks are called, consider the
4631 	 * I/O state again so that we can release or cancel I/O that
4632 	 * is not longer needed once the callbacks are satisfied.
4633 	 */
4634 
4635 	if (directory->details->in_async_service_loop) {
4636 		directory->details->state_changed = TRUE;
4637 		return;
4638 	}
4639 	directory->details->in_async_service_loop = TRUE;
4640 	nemo_directory_ref (directory);
4641 	do {
4642 		directory->details->state_changed = FALSE;
4643 		start_or_stop_io (directory);
4644 		if (call_ready_callbacks (directory)) {
4645 			directory->details->state_changed = TRUE;
4646 		}
4647 	} while (directory->details->state_changed);
4648 	directory->details->in_async_service_loop = FALSE;
4649 	nemo_directory_unref (directory);
4650 
4651 	/* Check if any directories should wake up. */
4652 	async_job_wake_up ();
4653 }
4654 
4655 void
nemo_directory_cancel(NemoDirectory * directory)4656 nemo_directory_cancel (NemoDirectory *directory)
4657 {
4658 	/* Arbitrary order (kept alphabetical). */
4659 	deep_count_cancel (directory);
4660 	directory_count_cancel (directory);
4661 	file_info_cancel (directory);
4662 	file_list_cancel (directory);
4663 	link_info_cancel (directory);
4664 	mime_list_cancel (directory);
4665 	new_files_cancel (directory);
4666 	extension_info_cancel (directory);
4667 	thumbnail_cancel (directory);
4668 	mount_cancel (directory);
4669 	filesystem_info_cancel (directory);
4670     favorite_check_cancel (directory);
4671 
4672 	/* We aren't waiting for anything any more. */
4673 	if (waiting_directories != NULL) {
4674 		g_hash_table_remove (waiting_directories, directory);
4675 	}
4676 
4677 	/* Check if any directories should wake up. */
4678 	async_job_wake_up ();
4679 }
4680 
4681 static void
cancel_directory_count_for_file(NemoDirectory * directory,NemoFile * file)4682 cancel_directory_count_for_file (NemoDirectory *directory,
4683 				 NemoFile      *file)
4684 {
4685 	if (directory->details->count_in_progress != NULL &&
4686 	    directory->details->count_in_progress->count_file == file) {
4687 		directory_count_cancel (directory);
4688 	}
4689 }
4690 
4691 static void
cancel_deep_counts_for_file(NemoDirectory * directory,NemoFile * file)4692 cancel_deep_counts_for_file (NemoDirectory *directory,
4693 			     NemoFile      *file)
4694 {
4695 	if (directory->details->deep_count_file == file) {
4696 		deep_count_cancel (directory);
4697 	}
4698 }
4699 
4700 static void
cancel_mime_list_for_file(NemoDirectory * directory,NemoFile * file)4701 cancel_mime_list_for_file (NemoDirectory *directory,
4702 			   NemoFile      *file)
4703 {
4704 	if (directory->details->mime_list_in_progress != NULL &&
4705 	    directory->details->mime_list_in_progress->mime_list_file == file) {
4706 		mime_list_cancel (directory);
4707 	}
4708 }
4709 
4710 static void
cancel_file_info_for_file(NemoDirectory * directory,NemoFile * file)4711 cancel_file_info_for_file (NemoDirectory *directory,
4712 			   NemoFile      *file)
4713 {
4714 	if (directory->details->get_info_file == file) {
4715 		file_info_cancel (directory);
4716 	}
4717 }
4718 
4719 static void
cancel_btime_for_file(NemoDirectory * directory,NemoFile * file)4720 cancel_btime_for_file (NemoDirectory *directory,
4721                        NemoFile      *file)
4722 {
4723     if (directory->details->get_btime_file == file) {
4724         btime_cancel (directory);
4725     }
4726 }
4727 
4728 static void
cancel_favorite_check_for_file(NemoDirectory * directory,NemoFile * file)4729 cancel_favorite_check_for_file (NemoDirectory *directory,
4730                                 NemoFile      *file)
4731 {
4732     if (directory->details->favorite_check_file == file) {
4733         favorite_check_cancel (directory);
4734     }
4735 }
4736 
4737 static void
cancel_thumbnail_for_file(NemoDirectory * directory,NemoFile * file)4738 cancel_thumbnail_for_file (NemoDirectory *directory,
4739 			   NemoFile      *file)
4740 {
4741 	if (directory->details->thumbnail_state != NULL &&
4742 	    directory->details->thumbnail_state->file == file) {
4743 		thumbnail_cancel (directory);
4744 	}
4745 }
4746 
4747 static void
cancel_mount_for_file(NemoDirectory * directory,NemoFile * file)4748 cancel_mount_for_file (NemoDirectory *directory,
4749 			   NemoFile      *file)
4750 {
4751 	if (directory->details->mount_state != NULL &&
4752 	    directory->details->mount_state->file == file) {
4753 		mount_cancel (directory);
4754 	}
4755 }
4756 
4757 static void
cancel_filesystem_info_for_file(NemoDirectory * directory,NemoFile * file)4758 cancel_filesystem_info_for_file (NemoDirectory *directory,
4759 				 NemoFile      *file)
4760 {
4761 	if (directory->details->filesystem_info_state != NULL &&
4762 	    directory->details->filesystem_info_state->file == file) {
4763 		filesystem_info_cancel (directory);
4764 	}
4765 }
4766 
4767 static void
cancel_link_info_for_file(NemoDirectory * directory,NemoFile * file)4768 cancel_link_info_for_file (NemoDirectory *directory,
4769 			   NemoFile      *file)
4770 {
4771 	if (directory->details->link_info_read_state != NULL &&
4772 	    directory->details->link_info_read_state->file == file) {
4773 		link_info_cancel (directory);
4774 	}
4775 }
4776 
4777 
4778 static void
cancel_loading_attributes(NemoDirectory * directory,NemoFileAttributes file_attributes)4779 cancel_loading_attributes (NemoDirectory *directory,
4780 			   NemoFileAttributes file_attributes)
4781 {
4782 	Request request;
4783 
4784 	request = nemo_directory_set_up_request (file_attributes);
4785 
4786 	if (REQUEST_WANTS_TYPE (request, REQUEST_DIRECTORY_COUNT)) {
4787 		directory_count_cancel (directory);
4788 	}
4789 	if (REQUEST_WANTS_TYPE (request, REQUEST_DEEP_COUNT)) {
4790 		deep_count_cancel (directory);
4791 	}
4792 	if (REQUEST_WANTS_TYPE (request, REQUEST_MIME_LIST)) {
4793 		mime_list_cancel (directory);
4794 	}
4795 	if (REQUEST_WANTS_TYPE (request, REQUEST_FILE_INFO)) {
4796 		file_info_cancel (directory);
4797 	}
4798     if (REQUEST_WANTS_TYPE (request, REQUEST_BTIME)) {
4799         btime_cancel (directory);
4800     }
4801 	if (REQUEST_WANTS_TYPE (request, REQUEST_FILESYSTEM_INFO)) {
4802 		filesystem_info_cancel (directory);
4803 	}
4804 	if (REQUEST_WANTS_TYPE (request, REQUEST_LINK_INFO)) {
4805 		link_info_cancel (directory);
4806 	}
4807 
4808 	if (REQUEST_WANTS_TYPE (request, REQUEST_EXTENSION_INFO)) {
4809 		extension_info_cancel (directory);
4810 	}
4811 
4812 	if (REQUEST_WANTS_TYPE (request, REQUEST_THUMBNAIL)) {
4813 		thumbnail_cancel (directory);
4814 	}
4815 
4816 	if (REQUEST_WANTS_TYPE (request, REQUEST_MOUNT)) {
4817 		mount_cancel (directory);
4818 	}
4819    if (REQUEST_WANTS_TYPE (request, REQUEST_FAVORITE_CHECK)) {
4820         favorite_check_cancel (directory);
4821     }
4822 	nemo_directory_async_state_changed (directory);
4823 }
4824 
4825 void
nemo_directory_cancel_loading_file_attributes(NemoDirectory * directory,NemoFile * file,NemoFileAttributes file_attributes)4826 nemo_directory_cancel_loading_file_attributes (NemoDirectory      *directory,
4827 						   NemoFile           *file,
4828 						   NemoFileAttributes  file_attributes)
4829 {
4830 	Request request;
4831 
4832 	nemo_directory_remove_file_from_work_queue (directory, file);
4833 
4834 	request = nemo_directory_set_up_request (file_attributes);
4835 
4836 	if (REQUEST_WANTS_TYPE (request, REQUEST_DIRECTORY_COUNT)) {
4837 		cancel_directory_count_for_file (directory, file);
4838 	}
4839 	if (REQUEST_WANTS_TYPE (request, REQUEST_DEEP_COUNT)) {
4840 		cancel_deep_counts_for_file (directory, file);
4841 	}
4842 	if (REQUEST_WANTS_TYPE (request, REQUEST_MIME_LIST)) {
4843 		cancel_mime_list_for_file (directory, file);
4844 	}
4845 	if (REQUEST_WANTS_TYPE (request, REQUEST_FILE_INFO)) {
4846 		cancel_file_info_for_file (directory, file);
4847 	}
4848     if (REQUEST_WANTS_TYPE (request, REQUEST_BTIME)) {
4849         cancel_btime_for_file (directory, file);
4850     }
4851 	if (REQUEST_WANTS_TYPE (request, REQUEST_FILESYSTEM_INFO)) {
4852 		cancel_filesystem_info_for_file (directory, file);
4853 	}
4854 	if (REQUEST_WANTS_TYPE (request, REQUEST_LINK_INFO)) {
4855 		cancel_link_info_for_file (directory, file);
4856 	}
4857 	if (REQUEST_WANTS_TYPE (request, REQUEST_THUMBNAIL)) {
4858 		cancel_thumbnail_for_file (directory, file);
4859 	}
4860 	if (REQUEST_WANTS_TYPE (request, REQUEST_MOUNT)) {
4861 		cancel_mount_for_file (directory, file);
4862 	}
4863     if (REQUEST_WANTS_TYPE (request, REQUEST_FAVORITE_CHECK)) {
4864         cancel_favorite_check_for_file (directory, file);
4865     }
4866 	nemo_directory_async_state_changed (directory);
4867 }
4868 
4869 void
nemo_directory_add_file_to_work_queue(NemoDirectory * directory,NemoFile * file)4870 nemo_directory_add_file_to_work_queue (NemoDirectory *directory,
4871 					   NemoFile *file)
4872 {
4873 	g_return_if_fail (file->details->directory == directory);
4874 
4875 	nemo_file_queue_enqueue (directory->details->high_priority_queue,
4876 				     file);
4877 }
4878 
4879 
4880 static void
add_all_files_to_work_queue(NemoDirectory * directory)4881 add_all_files_to_work_queue (NemoDirectory *directory)
4882 {
4883 	GList *node;
4884 	NemoFile *file;
4885 
4886 	for (node = directory->details->file_list; node != NULL; node = node->next) {
4887 		file = NEMO_FILE (node->data);
4888 
4889 		nemo_directory_add_file_to_work_queue (directory, file);
4890 	}
4891 }
4892 
4893 void
nemo_directory_remove_file_from_work_queue(NemoDirectory * directory,NemoFile * file)4894 nemo_directory_remove_file_from_work_queue (NemoDirectory *directory,
4895 						NemoFile *file)
4896 {
4897 	nemo_file_queue_remove (directory->details->high_priority_queue,
4898 				    file);
4899 	nemo_file_queue_remove (directory->details->low_priority_queue,
4900 				    file);
4901 	nemo_file_queue_remove (directory->details->extension_queue,
4902 				    file);
4903 }
4904 
4905 
4906 static void
move_file_to_low_priority_queue(NemoDirectory * directory,NemoFile * file)4907 move_file_to_low_priority_queue (NemoDirectory *directory,
4908 				 NemoFile *file)
4909 {
4910 	/* Must add before removing to avoid ref underflow */
4911 	nemo_file_queue_enqueue (directory->details->low_priority_queue,
4912 				     file);
4913 	nemo_file_queue_remove (directory->details->high_priority_queue,
4914 				    file);
4915 }
4916 
4917 static void
move_file_to_extension_queue(NemoDirectory * directory,NemoFile * file)4918 move_file_to_extension_queue (NemoDirectory *directory,
4919 			      NemoFile *file)
4920 {
4921 	/* Must add before removing to avoid ref underflow */
4922 	nemo_file_queue_enqueue (directory->details->extension_queue,
4923 				     file);
4924 	nemo_file_queue_remove (directory->details->low_priority_queue,
4925 				    file);
4926 }
4927