46
file_unlock_cb (gpointer user_data)
52
path = g_file_get_path (file);
53
g_message ("Unlocking file '%s'", path);
56
tracker_file_unlock (file);
57
g_object_unref (file);
63
get_tmp_file (GFile *file)
52
create_temporary_file (GFile *file,
55
GInputStream *input_stream;
56
GOutputStream *output_stream;
65
57
GFile *tmp_file, *parent;
66
gchar *tmp_name, *name;
68
/* Create a temporary, hidden file
69
* within the same directory */
58
gchar *dir, *name, *tmp_path;
63
if (!g_file_is_native (file)) {
66
uri = g_file_get_uri (file);
67
g_warning ("Could not create temporary file, file is not native: '%s'", uri);
73
/* Create input stream */
74
input_stream = G_INPUT_STREAM (g_file_read (file, NULL, &error));
77
g_critical ("Could not create temporary file, %s", error->message);
82
/* Create output stream in a tmp file */
70
83
parent = g_file_get_parent (file);
84
dir = g_file_get_path (parent);
85
g_object_unref (parent);
71
87
name = g_file_get_basename (file);
73
tmp_name = g_strdup_printf ("._tracker_%s", name);
74
tmp_file = g_file_get_child (parent, tmp_name);
76
g_object_unref (parent);
88
tmp_path = g_strdup_printf ("%s" G_DIR_SEPARATOR_S ".tracker-XXXXXX.%s",
93
mode = g_file_info_get_attribute_uint32 (file_info,
94
G_FILE_ATTRIBUTE_UNIX_MODE);
95
fd = g_mkstemp_full (tmp_path, O_WRONLY, mode);
97
output_stream = g_unix_output_stream_new (fd, TRUE);
99
/* Splice the original file into the tmp file */
100
g_output_stream_splice (output_stream,
102
G_OUTPUT_STREAM_SPLICE_CLOSE_SOURCE |
103
G_OUTPUT_STREAM_SPLICE_CLOSE_TARGET,
106
g_object_unref (output_stream);
107
g_object_unref (input_stream);
109
tmp_file = g_file_new_for_path (tmp_path);
113
g_critical ("Could not copy temporary file, %s", error->message);
114
g_error_free (error);
116
g_file_delete (tmp_file, NULL, NULL);
117
g_object_unref (tmp_file);
84
126
tracker_writeback_file_update_metadata (TrackerWriteback *writeback,
85
127
GPtrArray *values,
86
TrackerSparqlConnection *connection)
128
TrackerSparqlConnection *connection,
129
GCancellable *cancellable)
88
131
TrackerWritebackFileClass *writeback_file_class;
90
133
GFile *file, *tmp_file;
91
134
GFileInfo *file_info;
92
const gchar *urls[2] = { NULL, NULL };
94
136
const gchar * const *content_types;
95
137
const gchar *mime_type;
182
/* module does not support writeback for this file */
183
g_object_unref (file);
184
g_object_unref (file_info);
189
/* Copy to a temporary file so we can perform an atomic write on move */
190
tmp_file = create_temporary_file (file, file_info);
193
g_object_unref (file);
194
g_object_unref (file_info);
199
retval = (writeback_file_class->update_file_metadata) (TRACKER_WRITEBACK_FILE (writeback),
206
/* Delete the temporary file and preserve original */
207
g_file_delete (tmp_file, NULL, NULL);
209
/* Move back the modified file to the original location */
210
g_file_move (tmp_file, file,
211
G_FILE_COPY_OVERWRITE,
212
NULL, NULL, NULL, NULL);
215
g_object_unref (tmp_file);
147
216
g_object_unref (file_info);
150
g_message ("Locking file '%s' in order to write metadata", row[0]);
152
tracker_file_lock (file);
156
tracker_miner_manager_ignore_next_update (tracker_writeback_get_miner_manager (),
157
"org.freedesktop.Tracker1.Miner.Files",
160
/* A note on IgnoreNextUpdate + Writeback. Consider this situation
161
* I see with an application recording a video:
162
* - Application creates a resource for a video in the store and
164
* - Application starts writting the new video file.
165
* - Store tells writeback to write the new slo:location in the file
166
* - Writeback reaches this exact function and sends IgnoreNextUpdate,
167
* then tries to update metadata.
168
* - Miner-fs gets the IgnoreNextUpdate (sent by the line above).
169
* - Application is still recording the video, which gets translated
170
* into an original CREATED event plus multiple UPDATE events which
171
* are being merged at tracker-monitor level, still not notified to
173
* - TrackerWriteback tries to updte file metadata (line below) but cannot
174
* do it yet as application is still updating the file, thus, the real
175
* metadata update gets delayed until the application ends writing
177
* - Application ends writing the video.
178
* - Now TrackerWriteback really updates the file. This happened N seconds
179
* after we sent the IgnoreNextUpdate, being N the length of the video...
180
* - TrackerMonitor sends the merged CREATED event to TrackerMinerFS,
181
* detects the IgnoreNextUpdate request and in this case we ignore the
182
* IgnoreNextUpdate request as this is a CREATED event.
184
* Need to review the whole writeback+IgnoreNextUpdate mechanism to cope
185
* with situations like the one above.
188
retval = (writeback_file_class->update_file_metadata) (TRACKER_WRITEBACK_FILE (writeback),
189
tmp_file, values, connection);
192
* This timeout value was 3s before, which could have been in
193
* order to have miner-fs skip the updates we just made, something
194
* along the purpose of IgnoreNextUpdate.
196
* But this is a problem when the event being ignored is a CREATED
197
* event. This is, tracker-writeback modifies a file that was just
198
* created. If we ignore this in the miner-fs, it will never index
199
* it, and that is not good. As there is already the
200
* IgnoreNextUpdate mechanism in place, I'm moving this timeout
201
* value to 1s. So, once writeback has written the file, only 1s
202
* after will unlock it. This synchronizes well with the 2s timeout
203
* in the miner-fs between detecting the file update and the actual
206
g_timeout_add_seconds (1, file_unlock_cb, g_object_ref (file));
209
/* Move back the modified file to the original location */
210
g_file_move (tmp_file, file,
211
G_FILE_COPY_OVERWRITE,
212
NULL, NULL, NULL, NULL);
214
g_object_unref (tmp_file);
215
217
g_object_unref (file);