~noskcaj/ubuntu/vivid/thunar/1.6.4

« back to all changes in this revision

Viewing changes to thunar/thunar-io-jobs.c

  • Committer: Bazaar Package Importer
  • Author(s): Lionel Le Folgoc
  • Date: 2010-12-04 16:46:20 UTC
  • mto: (2.1.3 experimental) (1.3.1)
  • mto: This revision was merged to the branch mainline in revision 69.
  • Revision ID: james.westby@ubuntu.com-20101204164620-h7p4t2e9z6hfhz6l
Tags: upstream-1.1.4
ImportĀ upstreamĀ versionĀ 1.1.4

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* vi:set et ai sw=2 sts=2 ts=2: */
 
2
/*-
 
3
 * Copyright (c) 2009 Jannis Pohlmann <jannis@xfce.org>
 
4
 *
 
5
 * This program is free software; you can redistribute it and/or modify
 
6
 * it under the terms of the GNU General Public License as published by
 
7
 * the Free Software Foundation; either version 2 of the License, or
 
8
 * (at your option) any later version.
 
9
 *
 
10
 * This program is distributed in the hope that it will be useful,
 
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
13
 * General Public License for more details.
 
14
 *
 
15
 * You should have received a copy of the GNU General Public License
 
16
 * along with this program; if not, write to the Free Software
 
17
 * Foundation, Inc., 51 Franklin Street, Fifth Floor,
 
18
 * Boston, MA 02110-1301, USA.
 
19
 */
 
20
 
 
21
#ifdef HAVE_CONFIG_H
 
22
#include <config.h>
 
23
#endif
 
24
 
 
25
#include <gio/gio.h>
 
26
 
 
27
#include <thunar/thunar-enum-types.h>
 
28
#include <thunar/thunar-gio-extensions.h>
 
29
#include <thunar/thunar-io-scan-directory.h>
 
30
#include <thunar/thunar-io-jobs.h>
 
31
#include <thunar/thunar-job.h>
 
32
#include <thunar/thunar-private.h>
 
33
#include <thunar/thunar-simple-job.h>
 
34
#include <thunar/thunar-transfer-job.h>
 
35
 
 
36
 
 
37
 
 
38
static GList *
 
39
_tij_collect_nofollow (ThunarJob *job,
 
40
                       GList     *base_file_list,
 
41
                       GError   **error)
 
42
{
 
43
  GError *err = NULL;
 
44
  GList  *child_file_list = NULL;
 
45
  GList  *file_list = NULL;
 
46
  GList  *lp;
 
47
 
 
48
  /* recursively collect the files */
 
49
  for (lp = base_file_list; 
 
50
       err == NULL && lp != NULL && !exo_job_is_cancelled (EXO_JOB (job)); 
 
51
       lp = lp->next)
 
52
    {
 
53
      /* try to scan the directory */
 
54
      child_file_list = thunar_io_scan_directory (job, lp->data, 
 
55
                                                  G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, 
 
56
                                                  TRUE, &err);
 
57
 
 
58
      /* prepend the new files to the existing list */
 
59
      file_list = thunar_g_file_list_prepend (file_list, lp->data);
 
60
      file_list = g_list_concat (child_file_list, file_list);
 
61
    }
 
62
 
 
63
  /* check if we failed */
 
64
  if (err != NULL || exo_job_is_cancelled (EXO_JOB (job)))
 
65
    {
 
66
      if (exo_job_set_error_if_cancelled (EXO_JOB (job), error))
 
67
        g_error_free (err);
 
68
      else
 
69
        g_propagate_error (error, err);
 
70
 
 
71
      /* release the collected files */
 
72
      thunar_g_file_list_free (file_list);
 
73
 
 
74
      return NULL;
 
75
    }
 
76
 
 
77
  return file_list;
 
78
}
 
79
 
 
80
 
 
81
 
 
82
static gboolean
 
83
_thunar_io_jobs_create (ThunarJob   *job,
 
84
                        GValueArray *param_values,
 
85
                        GError     **error)
 
86
{
 
87
  GFileOutputStream *stream;
 
88
  ThunarJobResponse  response = THUNAR_JOB_RESPONSE_CANCEL;
 
89
  GFileInfo         *info;
 
90
  GError            *err = NULL;
 
91
  GList             *file_list;
 
92
  GList             *lp;
 
93
  gchar             *base_name;
 
94
  gchar             *display_name;
 
95
  
 
96
  _thunar_return_val_if_fail (THUNAR_IS_JOB (job), FALSE);
 
97
  _thunar_return_val_if_fail (param_values != NULL, FALSE);
 
98
  _thunar_return_val_if_fail (param_values->n_values == 1, FALSE);
 
99
  _thunar_return_val_if_fail (error == NULL || *error == NULL, FALSE);
 
100
 
 
101
  /* get the file list */
 
102
  file_list = g_value_get_boxed (g_value_array_get_nth (param_values, 0));
 
103
 
 
104
  /* we know the total amount of files to be processed */
 
105
  thunar_job_set_total_files (THUNAR_JOB (job), file_list);
 
106
 
 
107
  /* iterate over all files in the list */
 
108
  for (lp = file_list; 
 
109
       err == NULL && lp != NULL && !exo_job_is_cancelled (EXO_JOB (job)); 
 
110
       lp = lp->next)
 
111
    {
 
112
      g_assert (G_IS_FILE (lp->data));
 
113
 
 
114
      /* update progress information */
 
115
      thunar_job_processing_file (THUNAR_JOB (job), lp);
 
116
 
 
117
again:
 
118
      /* try to create the file */
 
119
      stream = g_file_create (lp->data, 
 
120
                              G_FILE_CREATE_NONE, 
 
121
                              exo_job_get_cancellable (EXO_JOB (job)),
 
122
                              &err);
 
123
 
 
124
      /* abort if the job was cancelled */
 
125
      if (exo_job_is_cancelled (EXO_JOB (job)))
 
126
        break;
 
127
 
 
128
      /* check if creating failed */
 
129
      if (stream == NULL)
 
130
        {
 
131
          if (err->code == G_IO_ERROR_EXISTS)
 
132
            {
 
133
              g_clear_error (&err);
 
134
 
 
135
              /* the file already exists, query its display name */
 
136
              info = g_file_query_info (lp->data,
 
137
                                        G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME,
 
138
                                        G_FILE_QUERY_INFO_NONE,
 
139
                                        exo_job_get_cancellable (EXO_JOB (job)),
 
140
                                        NULL);
 
141
 
 
142
              /* abort if the job was cancelled */
 
143
              if (exo_job_is_cancelled (EXO_JOB (job)))
 
144
                break;
 
145
 
 
146
              /* determine the display name, using the basename as a fallback */
 
147
              if (info != NULL)
 
148
                {
 
149
                  display_name = g_strdup (g_file_info_get_display_name (info));
 
150
                  g_object_unref (info);
 
151
                }
 
152
              else
 
153
                {
 
154
                  base_name = g_file_get_basename (lp->data);
 
155
                  display_name = g_filename_display_name (base_name);
 
156
                  g_free (base_name);
 
157
                }
 
158
 
 
159
              /* ask the user whether he wants to overwrite the existing file */
 
160
              response = thunar_job_ask_overwrite (THUNAR_JOB (job), 
 
161
                                                   _("The file \"%s\" already exists"), 
 
162
                                                   display_name);
 
163
 
 
164
              /* check if we should overwrite */
 
165
              if (response == THUNAR_JOB_RESPONSE_YES)
 
166
                {
 
167
                  /* try to remove the file. fail if not possible */
 
168
                  if (g_file_delete (lp->data, exo_job_get_cancellable (EXO_JOB (job)), &err))
 
169
                    goto again;
 
170
                }
 
171
              
 
172
              /* clean up */
 
173
              g_free (display_name);
 
174
            }
 
175
          else 
 
176
            {
 
177
              /* determine display name of the file */
 
178
              base_name = g_file_get_basename (lp->data);
 
179
              display_name = g_filename_display_basename (base_name);
 
180
              g_free (base_name);
 
181
 
 
182
              /* ask the user whether to skip/retry this path (cancels the job if not) */
 
183
              response = thunar_job_ask_skip (THUNAR_JOB (job), 
 
184
                                              _("Failed to create empty file \"%s\": %s"),
 
185
                                              display_name, err->message);
 
186
              g_free (display_name);
 
187
 
 
188
              g_clear_error (&err);
 
189
 
 
190
              /* go back to the beginning if the user wants to retry */
 
191
              if (response == THUNAR_JOB_RESPONSE_RETRY)
 
192
                goto again;
 
193
            }
 
194
        }
 
195
      else
 
196
        g_object_unref (stream);
 
197
    }
 
198
 
 
199
  /* check if we have failed */
 
200
  if (err != NULL)
 
201
    {
 
202
      g_propagate_error (error, err);
 
203
      return FALSE;
 
204
    }
 
205
 
 
206
  /* check if the job was cancelled */
 
207
  if (exo_job_is_cancelled (EXO_JOB (job)))
 
208
    return FALSE;
 
209
 
 
210
  /* emit the "new-files" signal with the given file list */
 
211
  thunar_job_new_files (THUNAR_JOB (job), file_list);
 
212
 
 
213
  return TRUE;
 
214
}
 
215
 
 
216
 
 
217
 
 
218
ThunarJob *
 
219
thunar_io_jobs_create_files (GList *file_list)
 
220
{
 
221
  return thunar_simple_job_launch (_thunar_io_jobs_create, 1,
 
222
                                   THUNAR_TYPE_G_FILE_LIST, file_list);
 
223
}
 
224
 
 
225
 
 
226
 
 
227
static gboolean
 
228
_thunar_io_jobs_mkdir (ThunarJob   *job,
 
229
                       GValueArray *param_values,
 
230
                       GError     **error)
 
231
{
 
232
  ThunarJobResponse response;
 
233
  GFileInfo        *info;
 
234
  GError           *err = NULL;
 
235
  GList            *file_list;
 
236
  GList            *lp;
 
237
  gchar            *base_name;
 
238
  gchar            *display_name;
 
239
 
 
240
  _thunar_return_val_if_fail (THUNAR_IS_JOB (job), FALSE);
 
241
  _thunar_return_val_if_fail (param_values != NULL, FALSE);
 
242
  _thunar_return_val_if_fail (param_values->n_values == 1, FALSE);
 
243
  _thunar_return_val_if_fail (error == NULL || *error == NULL, FALSE);
 
244
 
 
245
  file_list = g_value_get_boxed (g_value_array_get_nth (param_values, 0));
 
246
 
 
247
  /* we know the total list of files to process */
 
248
  thunar_job_set_total_files (THUNAR_JOB (job), file_list);
 
249
 
 
250
  for (lp = file_list; 
 
251
       err == NULL && lp != NULL && !exo_job_is_cancelled (EXO_JOB (job));
 
252
       lp = lp->next)
 
253
    {
 
254
      g_assert (G_IS_FILE (lp->data));
 
255
 
 
256
      /* update progress information */
 
257
      thunar_job_processing_file (THUNAR_JOB (job), lp);
 
258
 
 
259
again:
 
260
      /* try to create the directory */
 
261
      if (!g_file_make_directory (lp->data, exo_job_get_cancellable (EXO_JOB (job)), &err))
 
262
        {
 
263
          if (err->code == G_IO_ERROR_EXISTS)
 
264
            {
 
265
              g_error_free (err);
 
266
              err = NULL;
 
267
 
 
268
              /* abort if the job was cancelled */
 
269
              if (exo_job_is_cancelled (EXO_JOB (job)))
 
270
                break;
 
271
 
 
272
              /* the file already exists, query its display name */
 
273
              info = g_file_query_info (lp->data,
 
274
                                        G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME,
 
275
                                        G_FILE_QUERY_INFO_NONE,
 
276
                                        exo_job_get_cancellable (EXO_JOB (job)),
 
277
                                        NULL);
 
278
 
 
279
              /* abort if the job was cancelled */
 
280
              if (exo_job_is_cancelled (EXO_JOB (job)))
 
281
                break;
 
282
 
 
283
              /* determine the display name, using the basename as a fallback */
 
284
              if (info != NULL)
 
285
                {
 
286
                  display_name = g_strdup (g_file_info_get_display_name (info));
 
287
                  g_object_unref (info);
 
288
                }
 
289
              else
 
290
                {
 
291
                  base_name = g_file_get_basename (lp->data);
 
292
                  display_name = g_filename_display_name (base_name);
 
293
                  g_free (base_name);
 
294
                }
 
295
 
 
296
              /* ask the user whether he wants to overwrite the existing file */
 
297
              response = thunar_job_ask_overwrite (THUNAR_JOB (job), 
 
298
                                                   _("The file \"%s\" already exists"),
 
299
                                                   display_name);
 
300
 
 
301
              /* check if we should overwrite it */
 
302
              if (response == THUNAR_JOB_RESPONSE_YES)
 
303
                {
 
304
                  /* try to remove the file, fail if not possible */
 
305
                  if (g_file_delete (lp->data, exo_job_get_cancellable (EXO_JOB (job)), &err))
 
306
                    goto again;
 
307
                }
 
308
 
 
309
              /* clean up */
 
310
              g_free (display_name);
 
311
            }
 
312
          else
 
313
            {
 
314
              /* determine the display name of the file */
 
315
              base_name = g_file_get_basename (lp->data);
 
316
              display_name = g_filename_display_basename (base_name);
 
317
              g_free (base_name);
 
318
 
 
319
              /* ask the user whether to skip/retry this path (cancels the job if not) */
 
320
              response = thunar_job_ask_skip (THUNAR_JOB (job), 
 
321
                                              _("Failed to create directory \"%s\": %s"),
 
322
                                              display_name, err->message);
 
323
              g_free (display_name);
 
324
 
 
325
              g_error_free (err);
 
326
              err = NULL;
 
327
 
 
328
              /* go back to the beginning if the user wants to retry */
 
329
              if (response == THUNAR_JOB_RESPONSE_RETRY)
 
330
                goto again;
 
331
            }
 
332
        }
 
333
    }
 
334
 
 
335
  /* check if we have failed */
 
336
  if (err != NULL)
 
337
    {
 
338
      g_propagate_error (error, err);
 
339
      return FALSE;
 
340
    }
 
341
 
 
342
  /* check if the job was cancelled */
 
343
  if (exo_job_is_cancelled (EXO_JOB (job)))
 
344
    return FALSE;
 
345
 
 
346
  /* emit the "new-files" signal with the given file list */
 
347
  thunar_job_new_files (THUNAR_JOB (job), file_list);
 
348
  
 
349
  return TRUE;
 
350
}
 
351
 
 
352
 
 
353
 
 
354
ThunarJob *
 
355
thunar_io_jobs_make_directories (GList *file_list)
 
356
{
 
357
  return thunar_simple_job_launch (_thunar_io_jobs_mkdir, 1,
 
358
                                   THUNAR_TYPE_G_FILE_LIST, file_list);
 
359
}
 
360
 
 
361
 
 
362
 
 
363
static gboolean
 
364
_thunar_io_jobs_unlink (ThunarJob   *job,
 
365
                        GValueArray *param_values,
 
366
                        GError     **error)
 
367
{
 
368
  ThunarJobResponse response;
 
369
  GFileInfo        *info;
 
370
  GError           *err = NULL;
 
371
  GList            *file_list;
 
372
  GList            *lp;
 
373
  gchar            *base_name;
 
374
  gchar            *display_name;
 
375
 
 
376
  _thunar_return_val_if_fail (THUNAR_IS_JOB (job), FALSE);
 
377
  _thunar_return_val_if_fail (param_values != NULL, FALSE);
 
378
  _thunar_return_val_if_fail (param_values->n_values == 1, FALSE);
 
379
  _thunar_return_val_if_fail (error == NULL || *error == NULL, FALSE);
 
380
 
 
381
  /* get the file list */
 
382
  file_list = g_value_get_boxed (g_value_array_get_nth (param_values, 0));
 
383
 
 
384
  /* tell the user that we're preparing to unlink the files */
 
385
  exo_job_info_message (EXO_JOB (job), _("Preparing..."));
 
386
 
 
387
  /* recursively collect files for removal, not following any symlinks */
 
388
  file_list = _tij_collect_nofollow (job, file_list, &err);
 
389
 
 
390
  /* free the file list and fail if there was an error or the job was cancelled */
 
391
  if (err != NULL || exo_job_is_cancelled (EXO_JOB (job)))
 
392
    {
 
393
      if (exo_job_set_error_if_cancelled (EXO_JOB (job), error))
 
394
        g_error_free (err);
 
395
      else
 
396
        g_propagate_error (error, err);
 
397
 
 
398
      thunar_g_file_list_free (file_list);
 
399
      return FALSE;
 
400
    }
 
401
 
 
402
  /* we know the total list of files to process */
 
403
  thunar_job_set_total_files (THUNAR_JOB (job), file_list);
 
404
 
 
405
  /* remove all the files */
 
406
  for (lp = file_list; lp != NULL && !exo_job_is_cancelled (EXO_JOB (job)); lp = lp->next)
 
407
    {
 
408
      g_assert (G_IS_FILE (lp->data));
 
409
 
 
410
      /* skip root folders which cannot be deleted anyway */
 
411
      if (thunar_g_file_is_root (lp->data))
 
412
        continue;
 
413
 
 
414
again:
 
415
      /* try to delete the file */
 
416
      if (!g_file_delete (lp->data, exo_job_get_cancellable (EXO_JOB (job)), &err))
 
417
        {
 
418
          /* query the file info for the display name */
 
419
          info = g_file_query_info (lp->data, 
 
420
                                    G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME,
 
421
                                    G_FILE_QUERY_INFO_NONE, 
 
422
                                    exo_job_get_cancellable (EXO_JOB (job)), 
 
423
                                    NULL);
 
424
 
 
425
          /* abort if the job was cancelled */
 
426
          if (exo_job_is_cancelled (EXO_JOB (job)))
 
427
            {
 
428
              g_clear_error (&err);
 
429
              break;
 
430
            }
 
431
 
 
432
          /* determine the display name, using the basename as a fallback */
 
433
          if (info != NULL)
 
434
            {
 
435
              display_name = g_strdup (g_file_info_get_display_name (info));
 
436
              g_object_unref (info);
 
437
            }
 
438
          else
 
439
            {
 
440
              base_name = g_file_get_basename (lp->data);
 
441
              display_name = g_filename_display_name (base_name);
 
442
              g_free (base_name);
 
443
            }
 
444
 
 
445
          /* ask the user whether he wants to skip this file */
 
446
          response = thunar_job_ask_skip (THUNAR_JOB (job), 
 
447
                                          _("Could not delete file \"%s\": %s"), 
 
448
                                          display_name, err->message);
 
449
          g_free (display_name);
 
450
 
 
451
          /* clear the error */
 
452
          g_clear_error (&err);
 
453
 
 
454
          /* check whether to retry */
 
455
          if (response == THUNAR_JOB_RESPONSE_RETRY)
 
456
            goto again;
 
457
        }
 
458
    }
 
459
 
 
460
  /* release the file list */
 
461
  thunar_g_file_list_free (file_list);
 
462
 
 
463
  if (exo_job_set_error_if_cancelled (EXO_JOB (job), error))
 
464
    return FALSE;
 
465
  else
 
466
    return TRUE;
 
467
}
 
468
 
 
469
 
 
470
 
 
471
ThunarJob *
 
472
thunar_io_jobs_unlink_files (GList *file_list)
 
473
{
 
474
  return thunar_simple_job_launch (_thunar_io_jobs_unlink, 1,
 
475
                                   THUNAR_TYPE_G_FILE_LIST, file_list);
 
476
}
 
477
 
 
478
 
 
479
 
 
480
ThunarJob *
 
481
thunar_io_jobs_move_files (GList *source_file_list,
 
482
                           GList *target_file_list)
 
483
{
 
484
  ThunarJob *job;
 
485
 
 
486
  _thunar_return_val_if_fail (source_file_list != NULL, NULL);
 
487
  _thunar_return_val_if_fail (target_file_list != NULL, NULL);
 
488
  _thunar_return_val_if_fail (g_list_length (source_file_list) == g_list_length (target_file_list), NULL);
 
489
 
 
490
  job = thunar_transfer_job_new (source_file_list, target_file_list, 
 
491
                                 THUNAR_TRANSFER_JOB_MOVE);
 
492
  
 
493
  return THUNAR_JOB (exo_job_launch (EXO_JOB (job)));
 
494
}
 
495
 
 
496
 
 
497
 
 
498
ThunarJob *
 
499
thunar_io_jobs_copy_files (GList *source_file_list,
 
500
                           GList *target_file_list)
 
501
{
 
502
  ThunarJob *job;
 
503
 
 
504
  _thunar_return_val_if_fail (source_file_list != NULL, NULL);
 
505
  _thunar_return_val_if_fail (target_file_list != NULL, NULL);
 
506
  _thunar_return_val_if_fail (g_list_length (source_file_list) == g_list_length (target_file_list), NULL);
 
507
 
 
508
  job = thunar_transfer_job_new (source_file_list, target_file_list,
 
509
                                 THUNAR_TRANSFER_JOB_COPY);
 
510
 
 
511
  return THUNAR_JOB (exo_job_launch (EXO_JOB (job)));
 
512
}
 
513
 
 
514
 
 
515
 
 
516
static gboolean
 
517
_thunar_io_jobs_link (ThunarJob   *job,
 
518
                      GValueArray *param_values,
 
519
                      GError     **error)
 
520
{
 
521
  ThunarJobResponse response;
 
522
  GError           *err = NULL;
 
523
  GList            *new_files_list = NULL;
 
524
  GList            *source_file_list;
 
525
  GList            *sp;
 
526
  GList            *target_file_list;
 
527
  GList            *tp;
 
528
  gchar            *base_name;
 
529
  gchar            *display_name;
 
530
  gchar            *source_path;
 
531
 
 
532
  _thunar_return_val_if_fail (THUNAR_IS_JOB (job), FALSE);
 
533
  _thunar_return_val_if_fail (param_values != NULL, FALSE);
 
534
  _thunar_return_val_if_fail (param_values->n_values == 2, FALSE);
 
535
  _thunar_return_val_if_fail (error == NULL || *error == NULL, FALSE);
 
536
 
 
537
  source_file_list = g_value_get_boxed (g_value_array_get_nth (param_values, 0));
 
538
  target_file_list = g_value_get_boxed (g_value_array_get_nth (param_values, 1));
 
539
 
 
540
  /* we know the total list of paths to process */
 
541
  thunar_job_set_total_files (THUNAR_JOB (job), source_file_list);
 
542
 
 
543
  /* process all files */
 
544
  for (sp = source_file_list, tp = target_file_list;
 
545
       err == NULL && sp != NULL && tp != NULL;
 
546
       sp = sp->next, tp = tp->next)
 
547
    {
 
548
      _thunar_assert (G_IS_FILE (sp->data));
 
549
      _thunar_assert (G_IS_FILE (tp->data));
 
550
 
 
551
      /* update progress information */
 
552
      thunar_job_processing_file (THUNAR_JOB (job), sp);
 
553
 
 
554
again:
 
555
      source_path = g_file_get_path (sp->data);
 
556
 
 
557
      if (G_LIKELY (source_path != NULL))
 
558
        {
 
559
          /* try to create the symlink */
 
560
          g_file_make_symbolic_link (tp->data, source_path, 
 
561
                                     exo_job_get_cancellable (EXO_JOB (job)),
 
562
                                     &err);
 
563
 
 
564
          g_free (source_path);
 
565
 
 
566
          if (err == NULL)
 
567
            new_files_list = thunar_g_file_list_prepend (new_files_list, sp->data);
 
568
          else
 
569
            {
 
570
              /* check if we have an error from which we can recover */
 
571
              if (err->domain == G_IO_ERROR && err->code == G_IO_ERROR_EXISTS)
 
572
                {
 
573
                  /* ask the user whether he wants to overwrite the existing file */
 
574
                  response = thunar_job_ask_overwrite (THUNAR_JOB (job), "%s", 
 
575
                                                       err->message);
 
576
 
 
577
                  /* release the error */
 
578
                  g_clear_error (&err);
 
579
 
 
580
                  /* try to delete the file */
 
581
                  if (G_LIKELY (response == THUNAR_JOB_RESPONSE_YES))
 
582
                    {
 
583
                      /* try to remove the target file (fail if not possible) */
 
584
                      if (g_file_delete (tp->data, exo_job_get_cancellable (EXO_JOB (job)), &err))
 
585
                        goto again;
 
586
                    }
 
587
                }
 
588
            }
 
589
        }
 
590
      else
 
591
        {
 
592
          base_name = g_file_get_basename (sp->data);
 
593
          display_name = g_filename_display_name (base_name);
 
594
          g_set_error (&err, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
 
595
                       _("Could not create symbolic link to \"%s\" "
 
596
                         "because it is not a local file"), display_name);
 
597
          g_free (display_name);
 
598
          g_free (base_name);
 
599
        }
 
600
    }
 
601
 
 
602
  if (err != NULL)
 
603
    {
 
604
      thunar_g_file_list_free (new_files_list);
 
605
      g_propagate_error (error, err);
 
606
      return FALSE;
 
607
    }
 
608
  else
 
609
    {
 
610
      thunar_job_new_files (THUNAR_JOB (job), new_files_list);
 
611
      thunar_g_file_list_free (new_files_list);
 
612
      return TRUE;
 
613
    }
 
614
}
 
615
 
 
616
 
 
617
 
 
618
ThunarJob *
 
619
thunar_io_jobs_link_files (GList *source_file_list,
 
620
                           GList *target_file_list)
 
621
{
 
622
  _thunar_return_val_if_fail (source_file_list != NULL, NULL);
 
623
  _thunar_return_val_if_fail (target_file_list != NULL, NULL);
 
624
  _thunar_return_val_if_fail (g_list_length (source_file_list) == g_list_length (target_file_list), NULL);
 
625
 
 
626
  return thunar_simple_job_launch (_thunar_io_jobs_link, 2,
 
627
                                   THUNAR_TYPE_G_FILE_LIST, source_file_list,
 
628
                                   THUNAR_TYPE_G_FILE_LIST, target_file_list);
 
629
}
 
630
 
 
631
 
 
632
 
 
633
static gboolean
 
634
_thunar_io_jobs_trash (ThunarJob   *job,
 
635
                       GValueArray *param_values,
 
636
                       GError     **error)
 
637
{
 
638
  GError *err = NULL;
 
639
  GList  *file_list;
 
640
  GList  *lp;
 
641
 
 
642
  _thunar_return_val_if_fail (THUNAR_IS_JOB (job), FALSE);
 
643
  _thunar_return_val_if_fail (param_values != NULL, FALSE);
 
644
  _thunar_return_val_if_fail (param_values->n_values == 1, FALSE);
 
645
  _thunar_return_val_if_fail (error == NULL || *error == NULL, FALSE);
 
646
 
 
647
  file_list = g_value_get_boxed (g_value_array_get_nth (param_values, 0));
 
648
 
 
649
  if (exo_job_set_error_if_cancelled (EXO_JOB (job), error))
 
650
    return FALSE;
 
651
 
 
652
  for (lp = file_list; err == NULL && lp != NULL; lp = lp->next)
 
653
    {
 
654
      _thunar_assert (G_IS_FILE (lp->data));
 
655
      g_file_trash (lp->data, exo_job_get_cancellable (EXO_JOB (job)), &err);
 
656
    }
 
657
 
 
658
  if (err != NULL)
 
659
    {
 
660
      g_propagate_error (error, err);
 
661
      return FALSE;
 
662
    }
 
663
  else
 
664
    {
 
665
      return TRUE;
 
666
    }
 
667
}
 
668
 
 
669
 
 
670
 
 
671
ThunarJob *
 
672
thunar_io_jobs_trash_files (GList *file_list)
 
673
{
 
674
  _thunar_return_val_if_fail (file_list != NULL, NULL);
 
675
 
 
676
  return thunar_simple_job_launch (_thunar_io_jobs_trash, 1,
 
677
                                   THUNAR_TYPE_G_FILE_LIST, file_list);
 
678
}
 
679
 
 
680
 
 
681
 
 
682
ThunarJob *
 
683
thunar_io_jobs_restore_files (GList *source_file_list,
 
684
                              GList *target_file_list)
 
685
{
 
686
  ThunarJob *job;
 
687
 
 
688
  _thunar_return_val_if_fail (source_file_list != NULL, NULL);
 
689
  _thunar_return_val_if_fail (target_file_list != NULL, NULL);
 
690
  _thunar_return_val_if_fail (g_list_length (source_file_list) == g_list_length (target_file_list), NULL);
 
691
 
 
692
  job = thunar_transfer_job_new (source_file_list, target_file_list, 
 
693
                                 THUNAR_TRANSFER_JOB_MOVE);
 
694
 
 
695
  return THUNAR_JOB (exo_job_launch (EXO_JOB (job)));
 
696
}
 
697
 
 
698
 
 
699
 
 
700
static gboolean
 
701
_thunar_io_jobs_chown (ThunarJob   *job,
 
702
                       GValueArray *param_values,
 
703
                       GError     **error)
 
704
{
 
705
  ThunarJobResponse response;
 
706
  const gchar      *message;
 
707
  GFileInfo        *info;
 
708
  gboolean          recursive;
 
709
  GError           *err = NULL;
 
710
  GList            *file_list;
 
711
  GList            *lp;
 
712
  gint              uid;
 
713
  gint              gid;
 
714
 
 
715
  _thunar_return_val_if_fail (THUNAR_IS_JOB (job), FALSE);
 
716
  _thunar_return_val_if_fail (param_values != NULL, FALSE);
 
717
  _thunar_return_val_if_fail (param_values->n_values == 4, FALSE);
 
718
  _thunar_return_val_if_fail (error == NULL || *error == NULL, FALSE);
 
719
 
 
720
  file_list = g_value_get_boxed (g_value_array_get_nth (param_values, 0));
 
721
  uid = g_value_get_int (g_value_array_get_nth (param_values, 1));
 
722
  gid = g_value_get_int (g_value_array_get_nth (param_values, 2));
 
723
  recursive = g_value_get_boolean (g_value_array_get_nth (param_values, 3));
 
724
 
 
725
  _thunar_assert ((uid >= 0 || gid >= 0) && !(uid >= 0 && gid >= 0));
 
726
 
 
727
  /* collect the files for the chown operation */
 
728
  if (recursive)
 
729
    file_list = _tij_collect_nofollow (job, file_list, &err);
 
730
  else
 
731
    file_list = thunar_g_file_list_copy (file_list);
 
732
 
 
733
  if (err != NULL)
 
734
    {
 
735
      g_propagate_error (error, err);
 
736
      return FALSE;
 
737
    }
 
738
 
 
739
  /* we know the total list of files to process */
 
740
  thunar_job_set_total_files (THUNAR_JOB (job), file_list);
 
741
 
 
742
  /* change the ownership of all files */
 
743
  for (lp = file_list; lp != NULL && err == NULL; lp = lp->next)
 
744
    {
 
745
      /* update progress information */
 
746
      thunar_job_processing_file (THUNAR_JOB (job), lp);
 
747
 
 
748
      /* try to query information about the file */
 
749
      info = g_file_query_info (lp->data, 
 
750
                                G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME,
 
751
                                G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
 
752
                                exo_job_get_cancellable (EXO_JOB (job)),
 
753
                                &err);
 
754
 
 
755
      if (err != NULL)
 
756
        break;
 
757
 
 
758
retry_chown:
 
759
      if (uid >= 0)
 
760
        {
 
761
          /* try to change the owner UID */
 
762
          g_file_set_attribute_uint32 (lp->data,
 
763
                                       G_FILE_ATTRIBUTE_UNIX_UID, uid,
 
764
                                       G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
 
765
                                       exo_job_get_cancellable (EXO_JOB (job)),
 
766
                                       &err);
 
767
        }
 
768
      else if (gid >= 0)
 
769
        {
 
770
          /* try to change the owner GID */
 
771
          g_file_set_attribute_uint32 (lp->data,
 
772
                                       G_FILE_ATTRIBUTE_UNIX_GID, gid,
 
773
                                       G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
 
774
                                       exo_job_get_cancellable (EXO_JOB (job)),
 
775
                                       &err);
 
776
        }
 
777
 
 
778
      /* check if there was a recoverable error */
 
779
      if (err != NULL && !exo_job_is_cancelled (EXO_JOB (job)))
 
780
        {
 
781
          /* generate a useful error message */
 
782
          message = G_LIKELY (uid >= 0) ? _("Failed to change the owner of \"%s\": %s") 
 
783
                                        : _("Failed to change the group of \"%s\": %s");
 
784
 
 
785
          /* ask the user whether to skip/retry this file */
 
786
          response = thunar_job_ask_skip (THUNAR_JOB (job), message, 
 
787
                                          g_file_info_get_display_name (info),
 
788
                                          err->message);
 
789
 
 
790
          /* clear the error */
 
791
          g_clear_error (&err);
 
792
 
 
793
          /* check whether to retry */
 
794
          if (response == THUNAR_JOB_RESPONSE_RETRY)
 
795
            goto retry_chown;
 
796
        }
 
797
 
 
798
      /* release file information */
 
799
      g_object_unref (info);
 
800
    }
 
801
 
 
802
  /* release the file list */
 
803
  thunar_g_file_list_free (file_list);
 
804
 
 
805
  if (err != NULL)
 
806
    {
 
807
      g_propagate_error (error, err);
 
808
      return FALSE;
 
809
    }
 
810
  else
 
811
    {
 
812
      return TRUE;
 
813
    }
 
814
}
 
815
 
 
816
 
 
817
 
 
818
ThunarJob *
 
819
thunar_io_jobs_change_group (GFile    *file,
 
820
                             guint32   gid,
 
821
                             gboolean  recursive)
 
822
{
 
823
  GList file_list;
 
824
 
 
825
  _thunar_return_val_if_fail (G_IS_FILE (file), NULL);
 
826
 
 
827
  file_list.data = g_object_ref (file);
 
828
  file_list.next = NULL; 
 
829
  file_list.prev = NULL;
 
830
  
 
831
  return thunar_simple_job_launch (_thunar_io_jobs_chown, 4,
 
832
                                   THUNAR_TYPE_G_FILE_LIST, &file_list,
 
833
                                   G_TYPE_INT, -1,
 
834
                                   G_TYPE_INT, (gint) gid,
 
835
                                   G_TYPE_BOOLEAN, recursive);
 
836
 
 
837
  g_object_unref (file_list.data);
 
838
}
 
839
 
 
840
 
 
841
 
 
842
static gboolean
 
843
_thunar_io_jobs_chmod (ThunarJob   *job,
 
844
                       GValueArray *param_values,
 
845
                       GError     **error)
 
846
{
 
847
  ThunarJobResponse response;
 
848
  GFileInfo        *info;
 
849
  gboolean          recursive;
 
850
  GError           *err = NULL;
 
851
  GList            *file_list;
 
852
  GList            *lp;
 
853
  ThunarFileMode    dir_mask;
 
854
  ThunarFileMode    dir_mode;
 
855
  ThunarFileMode    file_mask;
 
856
  ThunarFileMode    file_mode;
 
857
  ThunarFileMode    mask;
 
858
  ThunarFileMode    mode;
 
859
  ThunarFileMode    old_mode;
 
860
  ThunarFileMode    new_mode;
 
861
 
 
862
  _thunar_return_val_if_fail (THUNAR_IS_JOB (job), FALSE);
 
863
  _thunar_return_val_if_fail (param_values != NULL, FALSE);
 
864
  _thunar_return_val_if_fail (param_values->n_values == 6, FALSE);
 
865
  _thunar_return_val_if_fail (error == NULL || *error == NULL, FALSE);
 
866
 
 
867
  file_list = g_value_get_boxed (g_value_array_get_nth (param_values, 0));
 
868
  dir_mask = g_value_get_flags (g_value_array_get_nth (param_values, 1));
 
869
  dir_mode = g_value_get_flags (g_value_array_get_nth (param_values, 2));
 
870
  file_mask = g_value_get_flags (g_value_array_get_nth (param_values, 3));
 
871
  file_mode = g_value_get_flags (g_value_array_get_nth (param_values, 4));
 
872
  recursive = g_value_get_boolean (g_value_array_get_nth (param_values, 5));
 
873
 
 
874
  /* collect the files for the chown operation */
 
875
  if (recursive)
 
876
    file_list = _tij_collect_nofollow (job, file_list, &err);
 
877
  else
 
878
    file_list = thunar_g_file_list_copy (file_list);
 
879
 
 
880
  if (err != NULL)
 
881
    {
 
882
      g_propagate_error (error, err);
 
883
      return FALSE;
 
884
    }
 
885
 
 
886
  /* we know the total list of files to process */
 
887
  thunar_job_set_total_files (THUNAR_JOB (job), file_list);
 
888
 
 
889
  /* change the ownership of all files */
 
890
  for (lp = file_list; lp != NULL && err == NULL; lp = lp->next)
 
891
    {
 
892
      /* update progress information */
 
893
      thunar_job_processing_file (THUNAR_JOB (job), lp);
 
894
 
 
895
      /* try to query information about the file */
 
896
      info = g_file_query_info (lp->data, 
 
897
                                G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME ","
 
898
                                G_FILE_ATTRIBUTE_STANDARD_TYPE ","
 
899
                                G_FILE_ATTRIBUTE_UNIX_MODE,
 
900
                                G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
 
901
                                exo_job_get_cancellable (EXO_JOB (job)),
 
902
                                &err);
 
903
 
 
904
      if (err != NULL)
 
905
        break;
 
906
 
 
907
retry_chown:
 
908
      /* different actions depending on the type of the file */
 
909
      if (g_file_info_get_file_type (info) == G_FILE_TYPE_DIRECTORY)
 
910
        {
 
911
          mask = dir_mask;
 
912
          mode = dir_mode;
 
913
        }
 
914
      else
 
915
        {
 
916
          mask = file_mask;
 
917
          mode = file_mode;
 
918
        }
 
919
 
 
920
      /* determine the current mode */
 
921
      old_mode = g_file_info_get_attribute_uint32 (info, G_FILE_ATTRIBUTE_UNIX_MODE);
 
922
 
 
923
      /* generate the new mode, taking the old mode (which contains file type 
 
924
       * information) into account */
 
925
      new_mode = ((old_mode & ~mask) | mode) & 07777;
 
926
 
 
927
      /* try to change the file mode */
 
928
      g_file_set_attribute_uint32 (lp->data,
 
929
                                   G_FILE_ATTRIBUTE_UNIX_MODE, new_mode,
 
930
                                   G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
 
931
                                   exo_job_get_cancellable (EXO_JOB (job)),
 
932
                                   &err);
 
933
 
 
934
      /* check if there was a recoverable error */
 
935
      if (err != NULL && !exo_job_is_cancelled (EXO_JOB (job)))
 
936
        {
 
937
          /* ask the user whether to skip/retry this file */
 
938
          response = thunar_job_ask_skip (job,
 
939
                                          _("Failed to change the permissions of \"%s\": %s"), 
 
940
                                          g_file_info_get_display_name (info),
 
941
                                          err->message);
 
942
 
 
943
          /* clear the error */
 
944
          g_clear_error (&err);
 
945
 
 
946
          /* check whether to retry */
 
947
          if (response == THUNAR_JOB_RESPONSE_RETRY)
 
948
            goto retry_chown;
 
949
        }
 
950
 
 
951
      /* release file information */
 
952
      g_object_unref (info);
 
953
    }
 
954
 
 
955
  /* release the file list */
 
956
  thunar_g_file_list_free (file_list);
 
957
 
 
958
  if (err != NULL)
 
959
    {
 
960
      g_propagate_error (error, err);
 
961
      return FALSE;
 
962
    }
 
963
  else
 
964
    {
 
965
      return TRUE;
 
966
    }
 
967
  return TRUE;
 
968
}
 
969
 
 
970
 
 
971
 
 
972
ThunarJob *
 
973
thunar_io_jobs_change_mode (GFile         *file,
 
974
                            ThunarFileMode dir_mask,
 
975
                            ThunarFileMode dir_mode,
 
976
                            ThunarFileMode file_mask,
 
977
                            ThunarFileMode file_mode,
 
978
                            gboolean       recursive)
 
979
{
 
980
  GList file_list;
 
981
 
 
982
  _thunar_return_val_if_fail (G_IS_FILE (file), NULL);
 
983
 
 
984
  file_list.data = g_object_ref (file);
 
985
  file_list.next = NULL; 
 
986
  file_list.prev = NULL;
 
987
  
 
988
  return thunar_simple_job_launch (_thunar_io_jobs_chmod, 6,
 
989
                                   THUNAR_TYPE_G_FILE_LIST, &file_list,
 
990
                                   THUNAR_TYPE_FILE_MODE, dir_mask,
 
991
                                   THUNAR_TYPE_FILE_MODE, dir_mode,
 
992
                                   THUNAR_TYPE_FILE_MODE, file_mask,
 
993
                                   THUNAR_TYPE_FILE_MODE, file_mode,
 
994
                                   G_TYPE_BOOLEAN, recursive);
 
995
 
 
996
  g_object_unref (file_list.data);
 
997
}
 
998
 
 
999
 
 
1000
 
 
1001
static gboolean
 
1002
_thunar_io_jobs_ls (ThunarJob   *job,
 
1003
                    GValueArray *param_values,
 
1004
                    GError     **error)
 
1005
{
 
1006
  ThunarFile *file;
 
1007
  GError     *err = NULL;
 
1008
  GFile      *directory;
 
1009
  GList      *file_list = NULL;
 
1010
  GList      *lp;
 
1011
  GList      *path_list;
 
1012
 
 
1013
  _thunar_return_val_if_fail (THUNAR_IS_JOB (job), FALSE);
 
1014
  _thunar_return_val_if_fail (param_values != NULL, FALSE);
 
1015
  _thunar_return_val_if_fail (param_values->n_values == 1, FALSE);
 
1016
  _thunar_return_val_if_fail (error == NULL || *error == NULL, FALSE);
 
1017
 
 
1018
  if (exo_job_set_error_if_cancelled (EXO_JOB (job), error))
 
1019
    return FALSE;
 
1020
 
 
1021
  /* determine the directory to list */
 
1022
  directory = g_value_get_object (g_value_array_get_nth (param_values, 0));
 
1023
 
 
1024
  /* make sure the object is valid */
 
1025
  _thunar_assert (G_IS_FILE (directory));
 
1026
 
 
1027
  /* collect directory contents (non-recursively) */
 
1028
  path_list = thunar_io_scan_directory (job, directory, 
 
1029
                                        G_FILE_QUERY_INFO_NONE, 
 
1030
                                        FALSE, &err);
 
1031
 
 
1032
  /* turn the GFile list into a ThunarFile list */
 
1033
  for (lp = g_list_last (path_list); 
 
1034
       err == NULL && !exo_job_is_cancelled (EXO_JOB (job)) && lp != NULL; 
 
1035
       lp = lp->prev)
 
1036
    {
 
1037
      file = thunar_file_get (lp->data, &err);
 
1038
      if (G_LIKELY (file != NULL))
 
1039
        file_list = g_list_prepend (file_list, file);
 
1040
    }
 
1041
 
 
1042
  /* free the GFile list */
 
1043
  thunar_g_file_list_free (path_list);
 
1044
 
 
1045
  /* abort on errors or cancellation */
 
1046
  if (err != NULL)
 
1047
    {
 
1048
      g_propagate_error (error, err);
 
1049
      return FALSE;
 
1050
    }
 
1051
  else if (exo_job_set_error_if_cancelled (EXO_JOB (job), &err))
 
1052
    {
 
1053
      g_propagate_error (error, err);
 
1054
      return FALSE;
 
1055
    }
 
1056
 
 
1057
  /* check if we have any files to report */
 
1058
  if (G_LIKELY (file_list != NULL))
 
1059
    {
 
1060
      /* emit the "files-ready" signal */
 
1061
      if (!thunar_job_files_ready (THUNAR_JOB (job), file_list))
 
1062
        {
 
1063
          /* none of the handlers took over the file list, so it's up to us
 
1064
           * to destroy it */
 
1065
          thunar_file_list_free (file_list);
 
1066
        }
 
1067
    }
 
1068
  
 
1069
  /* there should be no errors here */
 
1070
  _thunar_assert (err == NULL);
 
1071
 
 
1072
  /* propagate cancellation error */
 
1073
  if (exo_job_set_error_if_cancelled (EXO_JOB (job), &err))
 
1074
    {
 
1075
      g_propagate_error (error, err);
 
1076
      return FALSE;
 
1077
    }
 
1078
 
 
1079
  return TRUE;
 
1080
}
 
1081
 
 
1082
 
 
1083
 
 
1084
ThunarJob *
 
1085
thunar_io_jobs_list_directory (GFile *directory)
 
1086
{
 
1087
  _thunar_return_val_if_fail (G_IS_FILE (directory), NULL);
 
1088
  
 
1089
  return thunar_simple_job_launch (_thunar_io_jobs_ls, 1, G_TYPE_FILE, directory);
 
1090
}
 
1091
 
 
1092
 
 
1093
 
 
1094
static gboolean
 
1095
_thunar_io_jobs_rename_notify (ThunarFile *file)
 
1096
{
 
1097
  _thunar_return_val_if_fail (THUNAR_IS_FILE (file), FALSE);
 
1098
 
 
1099
  /* tell the associated folder that the file was renamed */
 
1100
  thunarx_file_info_renamed (THUNARX_FILE_INFO (file));
 
1101
 
 
1102
  /* emit the file changed signal */
 
1103
  thunar_file_changed (file);
 
1104
 
 
1105
  return FALSE;
 
1106
}
 
1107
 
 
1108
 
 
1109
 
 
1110
static gboolean
 
1111
_thunar_io_jobs_rename (ThunarJob   *job,
 
1112
                        GValueArray *param_values,
 
1113
                        GError     **error)
 
1114
{
 
1115
  const gchar *display_name;
 
1116
  ThunarFile  *file;
 
1117
  GError      *err = NULL;
 
1118
 
 
1119
  _thunar_return_val_if_fail (THUNAR_IS_JOB (job), FALSE);
 
1120
  _thunar_return_val_if_fail (param_values != NULL, FALSE);
 
1121
  _thunar_return_val_if_fail (param_values->n_values == 2, FALSE);
 
1122
  _thunar_return_val_if_fail (G_VALUE_HOLDS (&param_values->values[0], THUNAR_TYPE_FILE), FALSE);
 
1123
  _thunar_return_val_if_fail (G_VALUE_HOLDS_STRING (&param_values->values[1]), FALSE);
 
1124
  _thunar_return_val_if_fail (error == NULL || *error == NULL, FALSE);
 
1125
 
 
1126
  if (exo_job_set_error_if_cancelled (EXO_JOB (job), error))
 
1127
    return FALSE;
 
1128
 
 
1129
  /* determine the file and display name */
 
1130
  file = g_value_get_object (g_value_array_get_nth (param_values, 0));
 
1131
  display_name = g_value_get_string (g_value_array_get_nth (param_values, 1));
 
1132
 
 
1133
  /* try to rename the file */
 
1134
  if (thunar_file_rename (file, display_name, exo_job_get_cancellable (EXO_JOB (job)), TRUE, &err))
 
1135
    {
 
1136
      exo_job_send_to_mainloop (EXO_JOB (job), 
 
1137
                                (GSourceFunc) _thunar_io_jobs_rename_notify, 
 
1138
                                g_object_ref (file), g_object_unref);
 
1139
    }
 
1140
 
 
1141
  /* abort on errors or cancellation */
 
1142
  if (err != NULL)
 
1143
    {
 
1144
      g_propagate_error (error, err);
 
1145
      return FALSE;
 
1146
    }
 
1147
 
 
1148
  return TRUE;
 
1149
}
 
1150
 
 
1151
 
 
1152
 
 
1153
ThunarJob *
 
1154
thunar_io_jobs_rename_file (ThunarFile  *file,
 
1155
                            const gchar *display_name)
 
1156
{
 
1157
  _thunar_return_val_if_fail (THUNAR_IS_FILE (file), NULL);
 
1158
  _thunar_return_val_if_fail (g_utf8_validate (display_name, -1, NULL), NULL);
 
1159
 
 
1160
  return thunar_simple_job_launch (_thunar_io_jobs_rename, 2, 
 
1161
                                   THUNAR_TYPE_FILE, file, 
 
1162
                                   G_TYPE_STRING, display_name);
 
1163
}