1  /* GIO - GLib Input, Output and Streaming Library
2  *
3  * Copyright (C) Carl-Anton Ingmarsson 2011 <ca.ingmarsson@gmail.com>
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library 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  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General
16  * Public License along with this library; if not, write to the
17  * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18  * Boston, MA 02110-1301, USA.
19  *
20  * Author: Carl-Anton Ingmarsson <ca.ingmarsson@gmail.com>
21  */
22 
23 #include <glib/gi18n.h>
24 
25 #include "gvfsafpserver.h"
26 
27 #include "gvfsafpvolume.h"
28 
29 
30 struct _GVfsAfpVolumePrivate
31 {
32   GVfsAfpServer *server;
33   GVfsAfpConnection *conn;
34   gboolean mounted;
35 
36   guint16 attributes;
37   guint16 volume_id;
38 };
39 
40 G_DEFINE_TYPE_WITH_PRIVATE (GVfsAfpVolume, g_vfs_afp_volume, G_TYPE_OBJECT);
41 
42 static void
43 attention_cb (GVfsAfpConnection *conn, guint attention, GVfsAfpVolume *volume);
44 
45 static void
g_vfs_afp_volume_init(GVfsAfpVolume * volume)46 g_vfs_afp_volume_init (GVfsAfpVolume *volume)
47 {
48   GVfsAfpVolumePrivate *priv;
49 
50   volume->priv = priv = g_vfs_afp_volume_get_instance_private (volume);
51   priv->mounted = FALSE;
52 }
53 
54 static void
g_vfs_afp_volume_finalize(GObject * object)55 g_vfs_afp_volume_finalize (GObject *object)
56 {
57   GVfsAfpVolume *volume;
58   GVfsAfpVolumePrivate *priv;
59 
60   volume = G_VFS_AFP_VOLUME (object);
61   priv = volume->priv;
62   g_signal_handlers_disconnect_by_func (priv->conn, attention_cb, volume);
63 
64   G_OBJECT_CLASS (g_vfs_afp_volume_parent_class)->finalize (object);
65 }
66 
67 static void
g_vfs_afp_volume_class_init(GVfsAfpVolumeClass * klass)68 g_vfs_afp_volume_class_init (GVfsAfpVolumeClass *klass)
69 {
70   GObjectClass* object_class = G_OBJECT_CLASS (klass);
71 
72   object_class->finalize = g_vfs_afp_volume_finalize;
73 }
74 
75 GVfsAfpVolume *
g_vfs_afp_volume_new(GVfsAfpServer * server,GVfsAfpConnection * conn)76 g_vfs_afp_volume_new (GVfsAfpServer *server, GVfsAfpConnection *conn)
77 {
78   GVfsAfpVolume *volume;
79   GVfsAfpVolumePrivate *priv;
80 
81   g_return_val_if_fail (G_VFS_IS_AFP_SERVER (server), NULL);
82   g_return_val_if_fail (G_VFS_IS_AFP_CONNECTION (conn), NULL);
83 
84   volume = g_object_new (G_VFS_TYPE_AFP_VOLUME, NULL);
85   priv = volume->priv;
86 
87   priv->server = server;
88   priv->conn = conn;
89   g_signal_connect (priv->conn, "attention", G_CALLBACK (attention_cb), volume);
90 
91   return volume;
92 }
93 
94 gboolean
g_vfs_afp_volume_mount_sync(GVfsAfpVolume * volume,const char * volume_name,GCancellable * cancellable,GError ** error)95 g_vfs_afp_volume_mount_sync (GVfsAfpVolume *volume,
96                              const char    *volume_name,
97                              GCancellable  *cancellable,
98                              GError       **error)
99 {
100   GVfsAfpVolumePrivate *priv;
101   GVfsAfpCommand *comm;
102   GVfsAfpReply *reply;
103   AfpResultCode res_code;
104 
105   g_return_val_if_fail (G_VFS_IS_AFP_VOLUME (volume), FALSE);
106   g_return_val_if_fail (volume_name != NULL, FALSE);
107 
108   priv = volume->priv;
109 
110   /* Open Volume */
111   comm = g_vfs_afp_command_new (AFP_COMMAND_OPEN_VOL);
112   /* pad byte */
113   g_vfs_afp_command_put_byte (comm, 0);
114   /* Volume Bitmap */
115   g_vfs_afp_command_put_uint16 (comm, AFP_VOLUME_BITMAP_VOL_ID_BIT | AFP_VOLUME_BITMAP_ATTRIBUTE_BIT);
116 
117   /* VolumeName */
118   g_vfs_afp_command_put_pascal (comm, volume_name);
119 
120   /* TODO: password? */
121 
122   reply = g_vfs_afp_connection_send_command_sync (priv->conn, comm, cancellable,
123                                                   error);
124   g_object_unref (comm);
125   if (!reply)
126     return FALSE;
127 
128   res_code = g_vfs_afp_reply_get_result_code (reply);
129   if (res_code != AFP_RESULT_NO_ERROR)
130   {
131     g_object_unref (reply);
132 
133     if (res_code == AFP_RESULT_OBJECT_NOT_FOUND)
134     {
135       g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND,
136                            _("Volume doesn’t exist"));
137       return FALSE;
138     }
139 
140     goto generic_error;
141   }
142 
143   /* Volume Bitmap */
144   g_vfs_afp_reply_read_uint16 (reply, NULL);
145   /* Volume Attributes Bitmap */
146   g_vfs_afp_reply_read_uint16 (reply, &priv->attributes);
147   /* Volume ID */
148   g_vfs_afp_reply_read_uint16 (reply, &priv->volume_id);
149 
150   g_object_unref (reply);
151 
152   priv->mounted = TRUE;
153   return TRUE;
154 
155 generic_error:
156   g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
157                /* Translators: first %s is volumename and second servername */
158                _("Couldn’t load %s on %s"), volume_name,
159                g_vfs_afp_server_get_info(priv->server)->server_name);
160   return FALSE;
161 }
162 
163 guint16
g_vfs_afp_volume_get_attributes(GVfsAfpVolume * volume)164 g_vfs_afp_volume_get_attributes (GVfsAfpVolume *volume)
165 {
166   GVfsAfpVolumePrivate *priv = volume->priv;
167 
168   g_return_val_if_fail (priv->mounted, 0);
169 
170   return priv->attributes;
171 }
172 
173 guint16
g_vfs_afp_volume_get_id(GVfsAfpVolume * volume)174 g_vfs_afp_volume_get_id (GVfsAfpVolume *volume)
175 {
176   GVfsAfpVolumePrivate *priv = volume->priv;
177 
178   g_return_val_if_fail (priv->mounted, 0);
179 
180   return priv->volume_id;
181 }
182 
183 static void
get_vol_parms_cb(GObject * source_object,GAsyncResult * res,gpointer user_data)184 get_vol_parms_cb (GObject *source_object, GAsyncResult *res, gpointer user_data)
185 {
186   GVfsAfpConnection *connection = G_VFS_AFP_CONNECTION (source_object);
187   GTask *task = G_TASK (user_data);
188   GVfsAfpVolume *volume = G_VFS_AFP_VOLUME (g_task_get_source_object (task));
189   GVfsAfpVolumePrivate *priv = volume->priv;
190 
191   GVfsAfpReply *reply;
192   GError *err = NULL;
193   AfpResultCode res_code;
194 
195   guint16 vol_bitmap;
196   GFileInfo *info;
197 
198   guint64 bytes_free, bytes_total;
199 
200   reply = g_vfs_afp_connection_send_command_finish (connection, res, &err);
201   if (!reply)
202   {
203     g_task_return_error (task, err);
204     g_object_unref (task);
205     return;
206   }
207 
208   res_code = g_vfs_afp_reply_get_result_code (reply);
209   if (res_code != AFP_RESULT_NO_ERROR)
210   {
211     g_object_unref (reply);
212 
213     g_task_return_error (task, afp_result_code_to_gerror (res_code));
214     g_object_unref (task);
215     return;
216   }
217 
218   g_vfs_afp_reply_read_uint16 (reply, &vol_bitmap);
219 
220   info = g_file_info_new ();
221 
222   if (vol_bitmap & AFP_VOLUME_BITMAP_ATTRIBUTE_BIT)
223   {
224     guint16 vol_attrs_bitmap;
225 
226     g_vfs_afp_reply_read_uint16 (reply, &vol_attrs_bitmap);
227 
228     g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_FILESYSTEM_READONLY,
229                                        vol_attrs_bitmap & AFP_VOLUME_ATTRIBUTES_BITMAP_READ_ONLY);
230   }
231 
232   if (vol_bitmap & AFP_VOLUME_BITMAP_CREATE_DATE_BIT)
233   {
234     gint32 create_date;
235     gint64 create_date_local;
236 
237     g_vfs_afp_reply_read_int32 (reply, &create_date);
238 
239     create_date_local = g_vfs_afp_server_time_to_local_time (priv->server, create_date);
240     g_file_info_set_attribute_uint64 (info, G_FILE_ATTRIBUTE_TIME_CREATED,
241                                       create_date_local);
242   }
243 
244   if (vol_bitmap & AFP_VOLUME_BITMAP_MOD_DATE_BIT)
245   {
246     gint32 mod_date;
247     gint64 mod_date_local;
248 
249     g_vfs_afp_reply_read_int32 (reply, &mod_date);
250 
251     mod_date_local = g_vfs_afp_server_time_to_local_time (priv->server, mod_date);
252     g_file_info_set_attribute_uint64 (info, G_FILE_ATTRIBUTE_TIME_MODIFIED,
253                                       mod_date_local);
254   }
255 
256   if (vol_bitmap & AFP_VOLUME_BITMAP_EXT_BYTES_FREE_BIT)
257   {
258     g_vfs_afp_reply_read_uint64 (reply, &bytes_free);
259     g_file_info_set_attribute_uint64 (info, G_FILE_ATTRIBUTE_FILESYSTEM_FREE,
260                                       bytes_free);
261   }
262 
263   if (vol_bitmap & AFP_VOLUME_BITMAP_EXT_BYTES_TOTAL_BIT)
264   {
265     g_vfs_afp_reply_read_uint64 (reply, &bytes_total);
266     g_file_info_set_attribute_uint64 (info, G_FILE_ATTRIBUTE_FILESYSTEM_SIZE,
267                                       bytes_total);
268   }
269 
270   if (vol_bitmap & AFP_VOLUME_BITMAP_EXT_BYTES_FREE_BIT &&
271       vol_bitmap & AFP_VOLUME_BITMAP_EXT_BYTES_TOTAL_BIT)
272     g_file_info_set_attribute_uint64 (info, G_FILE_ATTRIBUTE_FILESYSTEM_USED,
273                                       bytes_total - bytes_free);
274 
275   g_object_unref (reply);
276 
277   g_task_return_pointer (task, info, g_object_unref);
278   g_object_unref (task);
279 }
280 
281 /*
282  * g_vfs_afp_volume_get_parms:
283  *
284  * @volume: a #GVfsAfpVolume
285  * @vol_bitmap: bitmap describing the parameters that should be received.
286  * @cancellable: optional #GCancellable object, %NULL to ignore.
287  * @callback: callback to call when the request is satisfied.
288  * @user_data: the data to pass to callback function.
289  *
290  * Asynchronously retrieves the parameters specified by @vol_bitmap from @volume
291  */
292 void
g_vfs_afp_volume_get_parms(GVfsAfpVolume * volume,guint16 vol_bitmap,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)293 g_vfs_afp_volume_get_parms (GVfsAfpVolume       *volume,
294                             guint16              vol_bitmap,
295                             GCancellable        *cancellable,
296                             GAsyncReadyCallback  callback,
297                             gpointer             user_data)
298 {
299   GVfsAfpVolumePrivate *priv;
300   GVfsAfpCommand *comm;
301   GTask *task;
302 
303   priv = volume->priv;
304 
305   comm = g_vfs_afp_command_new (AFP_COMMAND_GET_VOL_PARMS);
306   /* pad byte */
307   g_vfs_afp_command_put_byte (comm, 0);
308   /* Volume ID */
309   g_vfs_afp_command_put_uint16 (comm, priv->volume_id);
310   /* Volume Bitmap */
311   g_vfs_afp_command_put_uint16 (comm, vol_bitmap);
312 
313   task = g_task_new (volume, cancellable, callback, user_data);
314   g_task_set_source_tag (task, g_vfs_afp_volume_get_parms);
315 
316   g_vfs_afp_connection_send_command (priv->conn, comm, NULL, get_vol_parms_cb,
317                                      cancellable, task);
318   g_object_unref (comm);
319 }
320 
321 /*
322  * g_vfs_afp_volume_get_parms_finish:
323  *
324  * @volume: a #GVfsAfpVolume.
325  * @result: a #GAsyncResult.
326  * @error: a #GError, %NULL to ignore.
327  *
328  * Finalizes the asynchronous operation started by
329  * g_vfs_afp_volume_get_parms.
330  *
331  * Returns: (transfer full): A #GFileInfo with the requested parameters or %NULL
332  * on error.
333  */
334 GFileInfo *
g_vfs_afp_volume_get_parms_finish(GVfsAfpVolume * volume,GAsyncResult * result,GError ** error)335 g_vfs_afp_volume_get_parms_finish (GVfsAfpVolume  *volume,
336                                    GAsyncResult   *result,
337                                    GError         **error)
338 {
339   g_return_val_if_fail (g_task_is_valid (result, volume), NULL);
340   g_return_val_if_fail (g_async_result_is_tagged (result, g_vfs_afp_volume_get_parms), NULL);
341 
342   return g_task_propagate_pointer (G_TASK (result), error);
343 }
344 
345 typedef struct
346 {
347   gint16 fork_refnum;
348   GFileInfo *info;
349 } OpenForkData;
350 
351 static void
open_fork_data_free(OpenForkData * data)352 open_fork_data_free (OpenForkData *data)
353 {
354   g_object_unref (data->info);
355 
356   g_slice_free (OpenForkData, data);
357 }
358 
359 static void
open_fork_cb(GObject * source_object,GAsyncResult * result,gpointer user_data)360 open_fork_cb (GObject *source_object, GAsyncResult *result, gpointer user_data)
361 {
362   GVfsAfpConnection *conn = G_VFS_AFP_CONNECTION (source_object);
363   GTask *task = G_TASK (user_data);
364   GVfsAfpVolume *volume;
365   GVfsAfpVolumePrivate *priv;
366   GVfsAfpReply *reply;
367   GError *err = NULL;
368   AfpResultCode res_code;
369   gboolean res;
370 
371   OpenForkData *data;
372   guint16 file_bitmap;
373 
374   volume = G_VFS_AFP_VOLUME (g_task_get_source_object (task));
375   priv = volume->priv;
376 
377   reply = g_vfs_afp_connection_send_command_finish (conn, result, &err);
378   if (!reply)
379   {
380     g_task_return_error (task, err);
381     g_object_unref (task);
382     return;
383   }
384 
385   res_code = g_vfs_afp_reply_get_result_code (reply);
386   if (res_code != AFP_RESULT_NO_ERROR)
387   {
388     g_object_unref (reply);
389 
390     switch (res_code)
391     {
392       case AFP_RESULT_ACCESS_DENIED:
393         g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_PERMISSION_DENIED,
394                                  _("Permission denied"));
395         break;
396       case AFP_RESULT_OBJECT_NOT_FOUND:
397         g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_NOT_FOUND,
398                                  _("File doesn’t exist"));
399         break;
400       case AFP_RESULT_OBJECT_TYPE_ERR:
401         g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_IS_DIRECTORY,
402                                  _("File is directory"));
403         break;
404       case AFP_RESULT_TOO_MANY_FILES_OPEN:
405         g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_TOO_MANY_OPEN_FILES,
406                                  _("Too many files open"));
407         break;
408       default:
409         g_task_return_error (task, afp_result_code_to_gerror (res_code));
410         break;
411     }
412 
413     g_object_unref (task);
414     return;
415   }
416 
417   data = g_slice_new (OpenForkData);
418 
419   g_vfs_afp_reply_read_uint16 (reply, &file_bitmap);
420   g_vfs_afp_reply_read_int16  (reply, &data->fork_refnum);
421 
422   data->info = g_file_info_new ();
423   res = g_vfs_afp_server_fill_info (priv->server, data->info, reply, FALSE, file_bitmap, &err);
424   g_object_unref (reply);
425   if (!res)
426   {
427     g_task_return_error (task, err);
428     g_object_unref (task);
429     return;
430   }
431 
432   g_task_set_task_data (task, data, (GDestroyNotify)open_fork_data_free);
433   g_task_return_boolean (task, TRUE);
434   g_object_unref (task);
435 }
436 
437 /*
438  * g_vfs_afp_volume_open_fork:
439  *
440  * @volume: a #GVfsAfpVolume
441  * @filename: file to open fork for.
442  * @access_mode:
443  * @bitmap:
444  * @cancellable: optional #GCancellable object, %NULL to ignore.
445  * @callback: callback to call when the request is satisfied.
446  * @user_data: the data to pass to callback function.
447  *
448  * Asynchronously opens a fork corresponding to @filename with the requested
449  * access rights.
450  */
451 void
g_vfs_afp_volume_open_fork(GVfsAfpVolume * volume,const char * filename,guint16 access_mode,guint16 bitmap,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)452 g_vfs_afp_volume_open_fork (GVfsAfpVolume      *volume,
453                             const char         *filename,
454                             guint16             access_mode,
455                             guint16             bitmap,
456                             GCancellable       *cancellable,
457                             GAsyncReadyCallback callback,
458                             gpointer            user_data)
459 {
460   GVfsAfpVolumePrivate *priv;
461   GVfsAfpCommand *comm;
462   GTask *task;
463 
464   g_return_if_fail (G_VFS_IS_AFP_VOLUME (volume));
465 
466   priv = volume->priv;
467 
468   comm = g_vfs_afp_command_new (AFP_COMMAND_OPEN_FORK);
469   /* data fork */
470   g_vfs_afp_command_put_byte (comm, 0);
471 
472   /* Volume ID */
473   g_vfs_afp_command_put_uint16 (comm, g_vfs_afp_volume_get_id (volume));
474   /* Directory ID */
475   g_vfs_afp_command_put_uint32 (comm, 2);
476 
477   /* Bitmap */
478   g_vfs_afp_command_put_uint16 (comm, bitmap);
479 
480   /* AccessMode */
481   g_vfs_afp_command_put_uint16 (comm, access_mode);
482 
483   /* Pathname */
484   g_vfs_afp_command_put_pathname (comm, filename);
485 
486   task = g_task_new (volume, cancellable, callback, user_data);
487   g_task_set_source_tag (task, g_vfs_afp_volume_open_fork);
488 
489   g_vfs_afp_connection_send_command (priv->conn, comm, NULL,
490                                      open_fork_cb, cancellable, task);
491   g_object_unref (comm);
492 }
493 
494 /*
495  * g_vfs_afp_volume_open_fork_finish:
496  *
497  * @volume: a #GVfsAfpVolume.
498  * @result: a #GAsyncResult.
499  * @fork_refnum: (out) the reference id of the newly opened fork.
500  * @info: (out callee-allocates) a #GFileInfo containing the requested parameters.
501  * @error: a #GError, %NULL to ignore.
502  *
503  * Finalizes the asynchronous operation started by
504  * g_vfs_afp_volume_open_fork.
505  *
506  * Returns: %TRUE on success, %FALSE on error.
507  */
508 gboolean
g_vfs_afp_volume_open_fork_finish(GVfsAfpVolume * volume,GAsyncResult * res,gint16 * fork_refnum,GFileInfo ** info,GError ** error)509 g_vfs_afp_volume_open_fork_finish (GVfsAfpVolume  *volume,
510                                    GAsyncResult   *res,
511                                    gint16         *fork_refnum,
512                                    GFileInfo      **info,
513                                    GError         **error)
514 {
515   OpenForkData *data;
516 
517   g_return_val_if_fail (g_task_is_valid (res, volume), FALSE);
518   g_return_val_if_fail (g_async_result_is_tagged (res, g_vfs_afp_volume_open_fork), FALSE);
519 
520   if (!g_task_propagate_boolean (G_TASK (res), error))
521     return FALSE;
522 
523   data = g_task_get_task_data (G_TASK (res));
524   if (fork_refnum)
525     *fork_refnum = data->fork_refnum;
526   if (info)
527     *info = g_object_ref (data->info);
528 
529   return TRUE;
530 }
531 
532 static void
close_fork_cb(GObject * source_object,GAsyncResult * res,gpointer user_data)533 close_fork_cb (GObject *source_object, GAsyncResult *res, gpointer user_data)
534 {
535   GVfsAfpConnection *conn = G_VFS_AFP_CONNECTION (source_object);
536   GTask *task = G_TASK (user_data);
537 
538   GVfsAfpReply *reply;
539   GError *err = NULL;
540   AfpResultCode res_code;
541 
542   reply = g_vfs_afp_connection_send_command_finish (conn, res, &err);
543   if (!reply)
544   {
545     g_task_return_error (task, err);
546     g_object_unref (task);
547     return;
548   }
549 
550   res_code = g_vfs_afp_reply_get_result_code (reply);
551   g_object_unref (reply);
552 
553   if (res_code != AFP_RESULT_NO_ERROR)
554   {
555     g_task_return_error (task, afp_result_code_to_gerror (res_code));
556     g_object_unref (task);
557     return;
558   }
559 
560   g_task_return_boolean (task, TRUE);
561   g_object_unref (task);
562 }
563 
564 /*
565  * g_vfs_afp_volume_close_fork:
566  *
567  * @volume: a #GVfsAfpVolume.
568  * @fork_refnum: the reference id of the fork which is to be closed.
569  * @cancellable: optional #GCancellable object, %NULL to ignore.
570  * @callback: callback to call when the request is satisfied.
571  * @user_data: the data to pass to callback function.
572  *
573  * Asynchronously closes an open fork specified by @fork_refnum.
574  */
575 void
g_vfs_afp_volume_close_fork(GVfsAfpVolume * volume,gint16 fork_refnum,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)576 g_vfs_afp_volume_close_fork (GVfsAfpVolume       *volume,
577                              gint16               fork_refnum,
578                              GCancellable        *cancellable,
579                              GAsyncReadyCallback  callback,
580                              gpointer             user_data)
581 {
582   GVfsAfpVolumePrivate *priv;
583   GVfsAfpCommand *comm;
584   GTask *task;
585 
586   g_return_if_fail (G_VFS_IS_AFP_VOLUME (volume));
587 
588   priv = volume->priv;
589 
590   comm = g_vfs_afp_command_new (AFP_COMMAND_CLOSE_FORK);
591   /* pad byte */
592   g_vfs_afp_command_put_byte (comm, 0);
593 
594   /* OForkRefNum */
595   g_vfs_afp_command_put_int16 (comm, fork_refnum);
596 
597   task = g_task_new (volume, cancellable, callback, user_data);
598   g_task_set_source_tag (task, g_vfs_afp_volume_close_fork);
599 
600   g_vfs_afp_connection_send_command (priv->conn, comm, NULL,
601                                      close_fork_cb, cancellable, task);
602   g_object_unref (comm);
603 }
604 
605 /*
606  * g_vfs_afp_volume_close_fork_finish:
607  *
608  * @volume: a #GVfsAfpVolume.
609  * @result: a #GAsyncResult.
610  * @error: a #GError, %NULL to ignore.
611  *
612  * Finalizes the asynchronous operation started by
613  * g_vfs_afp_volume_close_fork.
614  *
615  * Returns: %TRUE on success, %FALSE on error.
616  */
617 gboolean
g_vfs_afp_volume_close_fork_finish(GVfsAfpVolume * volume,GAsyncResult * result,GError ** error)618 g_vfs_afp_volume_close_fork_finish (GVfsAfpVolume  *volume,
619                                     GAsyncResult   *result,
620                                     GError         **error)
621 {
622   g_return_val_if_fail (g_task_is_valid (result, volume), FALSE);
623   g_return_val_if_fail (g_async_result_is_tagged (result, g_vfs_afp_volume_close_fork), FALSE);
624 
625   return g_task_propagate_boolean (G_TASK (result), error);
626 }
627 
628 static void
delete_cb(GObject * source_object,GAsyncResult * res,gpointer user_data)629 delete_cb (GObject *source_object, GAsyncResult *res, gpointer user_data)
630 {
631   GVfsAfpConnection *conn = G_VFS_AFP_CONNECTION (source_object);
632   GTask *task = G_TASK (user_data);
633 
634   GVfsAfpReply *reply;
635   GError *err = NULL;
636   AfpResultCode res_code;
637 
638   reply = g_vfs_afp_connection_send_command_finish (conn, res, &err);
639   if (!reply)
640   {
641     g_task_return_error (task, err);
642     g_object_unref (task);
643     return;
644   }
645 
646   res_code = g_vfs_afp_reply_get_result_code (reply);
647   g_object_unref (reply);
648 
649   if (res_code != AFP_RESULT_NO_ERROR)
650   {
651     switch (res_code)
652     {
653       case AFP_RESULT_ACCESS_DENIED:
654         g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_PERMISSION_DENIED,
655                                  _("Permission denied"));
656         break;
657       case AFP_RESULT_FILE_BUSY:
658         g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_BUSY,
659                                  _("Target file is open"));
660         break;
661       case AFP_RESULT_DIR_NOT_EMPTY:
662         g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_NOT_EMPTY,
663                                  _("Directory not empty"));
664         break;
665       case AFP_RESULT_OBJECT_LOCKED:
666         g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_FAILED,
667                                  _("Target object is marked as not deletable (DeleteInhibit)"));
668         break;
669       case AFP_RESULT_OBJECT_NOT_FOUND:
670         g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_NOT_FOUND,
671                                  _("Target object doesn’t exist"));
672         break;
673       case AFP_RESULT_VOL_LOCKED:
674         g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_PERMISSION_DENIED,
675                                  _("Volume is read-only"));
676         break;
677       default:
678         g_task_return_error (task, afp_result_code_to_gerror (res_code));
679         break;
680     }
681 
682     g_object_unref (task);
683     return;
684   }
685 
686   g_task_return_boolean (task, TRUE);
687   g_object_unref (task);
688 }
689 
690 /*
691  * g_vfs_afp_volume_delete:
692  *
693  * @volume: a #GVfsAfpVolume.
694  * @filename: file to delete.
695  * @cancellable: optional #GCancellable object, %NULL to ignore.
696  * @callback: callback to call when the request is satisfied.
697  * @user_data: the data to pass to callback function.
698  *
699  * Asynchronously deletes the file @filename.
700  */
701 void
g_vfs_afp_volume_delete(GVfsAfpVolume * volume,const char * filename,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)702 g_vfs_afp_volume_delete (GVfsAfpVolume       *volume,
703                          const char          *filename,
704                          GCancellable        *cancellable,
705                          GAsyncReadyCallback  callback,
706                          gpointer             user_data)
707 {
708   GVfsAfpVolumePrivate *priv;
709   GVfsAfpCommand *comm;
710   GTask *task;
711 
712   g_return_if_fail (G_VFS_IS_AFP_VOLUME (volume));
713 
714   priv = volume->priv;
715 
716   comm = g_vfs_afp_command_new (AFP_COMMAND_DELETE);
717   /* pad byte */
718   g_vfs_afp_command_put_byte (comm, 0);
719   /* Volume ID */
720   g_vfs_afp_command_put_uint16 (comm, g_vfs_afp_volume_get_id (volume));
721   /* Directory ID 2 == / */
722   g_vfs_afp_command_put_uint32 (comm, 2);
723 
724   /* Pathname */
725   g_vfs_afp_command_put_pathname (comm, filename);
726 
727   task = g_task_new (volume, cancellable, callback, user_data);
728   g_task_set_source_tag (task, g_vfs_afp_volume_delete);
729 
730   g_vfs_afp_connection_send_command (priv->conn, comm, NULL,
731                                      delete_cb, cancellable, task);
732   g_object_unref (comm);
733 }
734 
735 /*
736  * g_vfs_afp_volume_delete_finish:
737  *
738  * @volume: a #GVfsAfpVolume.
739  * @result: a #GAsyncResult.
740  * @error: a #GError, %NULL to ignore.
741  *
742  * Finalizes the asynchronous operation started by
743  * g_vfs_afp_volume_delete.
744  *
745  * Returns: %TRUE on success, %FALSE on error.
746  */
747 gboolean
g_vfs_afp_volume_delete_finish(GVfsAfpVolume * volume,GAsyncResult * result,GError ** error)748 g_vfs_afp_volume_delete_finish (GVfsAfpVolume  *volume,
749                                 GAsyncResult   *result,
750                                 GError         **error)
751 {
752   g_return_val_if_fail (g_task_is_valid (result, volume), FALSE);
753   g_return_val_if_fail (g_async_result_is_tagged (result, g_vfs_afp_volume_delete), FALSE);
754 
755   return g_task_propagate_boolean (G_TASK (result), error);
756 }
757 
758 typedef struct
759 {
760   char *filename;
761   gboolean hard_create;
762 } CreateFileData;
763 
764 static void
create_file_data_free(CreateFileData * cfd)765 create_file_data_free (CreateFileData *cfd)
766 {
767   g_free (cfd->filename);
768 
769   g_slice_free (CreateFileData, cfd);
770 }
771 
772 static void
create_file_cb(GObject * object,GAsyncResult * res,gpointer user_data)773 create_file_cb (GObject *object, GAsyncResult *res, gpointer user_data)
774 {
775   GVfsAfpConnection *conn = G_VFS_AFP_CONNECTION (object);
776   GTask *task = G_TASK (user_data);
777 
778   GVfsAfpReply *reply;
779   GError *err = NULL;
780   AfpResultCode res_code;
781 
782 
783   reply = g_vfs_afp_connection_send_command_finish (conn, res, &err);
784   if (!reply)
785   {
786     g_task_return_error (task, err);
787     g_object_unref (task);
788     return;
789   }
790 
791   res_code = g_vfs_afp_reply_get_result_code (reply);
792   g_object_unref (reply);
793   if (res_code != AFP_RESULT_NO_ERROR)
794   {
795     switch (res_code)
796     {
797       case AFP_RESULT_ACCESS_DENIED:
798         g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_PERMISSION_DENIED,
799                                  _("Permission denied"));
800         break;
801       case AFP_RESULT_DISK_FULL:
802         g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_NO_SPACE,
803                                  _("Not enough space on volume"));
804         break;
805       case AFP_RESULT_FILE_BUSY:
806         g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_EXISTS,
807                                  _("Target file is open"));
808         break;
809       case AFP_RESULT_OBJECT_EXISTS:
810         g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_EXISTS,
811                                  _("Target file already exists"));
812         break;
813       case AFP_RESULT_OBJECT_NOT_FOUND:
814         g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_NOT_FOUND,
815                                  _("Ancestor directory doesn’t exist"));
816         break;
817       case AFP_RESULT_VOL_LOCKED:
818         g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_PERMISSION_DENIED,
819                                  _("Volume is read-only"));
820         break;
821       default:
822         g_task_return_error (task, afp_result_code_to_gerror (res_code));
823         break;
824     }
825 
826     g_object_unref (task);
827     return;
828   }
829 
830   g_task_return_boolean (task, TRUE);
831   g_object_unref (task);
832 }
833 
834 static void
create_file_get_filedir_parms_cb(GObject * source_object,GAsyncResult * res,gpointer user_data)835 create_file_get_filedir_parms_cb (GObject *source_object, GAsyncResult *res, gpointer user_data)
836 {
837   GVfsAfpVolume *volume = G_VFS_AFP_VOLUME (source_object);
838   GVfsAfpVolumePrivate *priv = volume->priv;
839   GTask *task = G_TASK (user_data);
840   CreateFileData *cfd = g_task_get_task_data (task);
841 
842   GFileInfo *info;
843   GError *err = NULL;
844 
845   guint32 dir_id;
846   char *basename;
847   GVfsAfpCommand *comm;
848 
849   info = g_vfs_afp_volume_get_filedir_parms_finish (volume, res, &err);
850   if (!info)
851   {
852     g_task_return_error (task, err);
853     g_object_unref (task);
854     return;
855   }
856 
857   dir_id = g_file_info_get_attribute_uint32 (info, G_FILE_ATTRIBUTE_AFP_NODE_ID);
858   g_object_unref (info);
859 
860   comm = g_vfs_afp_command_new (AFP_COMMAND_CREATE_FILE);
861   /* soft/hard create */
862   g_vfs_afp_command_put_byte (comm, cfd->hard_create ? 0x80 : 0x00);
863   /* Volume ID */
864   g_vfs_afp_command_put_uint16 (comm, g_vfs_afp_volume_get_id (volume));
865   /* Directory ID */
866   g_vfs_afp_command_put_uint32 (comm, dir_id);
867 
868   /* Pathname */
869   basename = g_path_get_basename (cfd->filename);
870   g_vfs_afp_command_put_pathname (comm, basename);
871   g_free (basename);
872 
873   g_vfs_afp_connection_send_command (priv->conn, comm, NULL, create_file_cb,
874                                      g_task_get_cancellable (task), task);
875   g_object_unref (comm);
876 }
877 
878 /*
879  * g_vfs_afp_volume_create_file:
880  *
881  * @volume: a #GVfsAfpVolume.
882  * @filename: path to the new file to create.
883  * @hard_create: if %TRUE this call will overwrite an already existing file.
884  * If %FALSE it will error out instead.
885  * @cancellable: optional #GCancellable object, %NULL to ignore.
886  * @callback: callback to call when the request is satisfied.
887  * @user_data: the data to pass to callback function.
888  *
889  * Asynchronously creates a file at @filename.
890  */
891 void
g_vfs_afp_volume_create_file(GVfsAfpVolume * volume,const char * filename,gboolean hard_create,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)892 g_vfs_afp_volume_create_file (GVfsAfpVolume      *volume,
893                               const char         *filename,
894                               gboolean            hard_create,
895                               GCancellable       *cancellable,
896                               GAsyncReadyCallback callback,
897                               gpointer            user_data)
898 {
899   CreateFileData *cfd;
900   GTask *task;
901   char *dirname;
902 
903   cfd = g_slice_new0 (CreateFileData);
904   cfd->filename = g_strdup (filename);
905   cfd->hard_create = hard_create;
906 
907   task = g_task_new (volume, cancellable, callback, user_data);
908   g_task_set_source_tag (task, g_vfs_afp_volume_create_file);
909   g_task_set_task_data (task, cfd, (GDestroyNotify)create_file_data_free);
910 
911   dirname = g_path_get_dirname (filename);
912   g_vfs_afp_volume_get_filedir_parms (volume, dirname, 0, AFP_DIR_BITMAP_NODE_ID_BIT,
913                                       cancellable, create_file_get_filedir_parms_cb, task);
914   g_free (dirname);
915 }
916 
917 /*
918  * g_vfs_afp_volume_create_file_finish:
919  *
920  * @volume: a #GVfsAfpVolume.
921  * @result: a #GAsyncResult.
922  * @error: a #GError, %NULL to ignore.
923  *
924  * Finalizes the asynchronous operation started by
925  * g_vfs_afp_volume_create_file.
926  *
927  * Returns: %TRUE on success, %FALSE on error.
928  */
929 gboolean
g_vfs_afp_volume_create_file_finish(GVfsAfpVolume * volume,GAsyncResult * result,GError ** error)930 g_vfs_afp_volume_create_file_finish (GVfsAfpVolume  *volume,
931                                      GAsyncResult   *result,
932                                      GError         **error)
933 {
934   g_return_val_if_fail (g_task_is_valid (result, volume), FALSE);
935   g_return_val_if_fail (g_async_result_is_tagged (result, g_vfs_afp_volume_create_file), FALSE);
936 
937   return g_task_propagate_boolean (G_TASK (result), error);
938 }
939 
940 typedef struct
941 {
942   char *basename;
943 } CreateDirData;
944 
945 static void
create_dir_data_free(CreateDirData * cdd)946 create_dir_data_free (CreateDirData *cdd)
947 {
948   g_free (cdd->basename);
949 
950   g_slice_free (CreateDirData, cdd);
951 }
952 
953 static void
make_directory_cb(GObject * source_object,GAsyncResult * res,gpointer user_data)954 make_directory_cb (GObject *source_object, GAsyncResult *res, gpointer user_data)
955 {
956   GVfsAfpConnection *conn = G_VFS_AFP_CONNECTION (source_object);
957   GTask *task = G_TASK (user_data);
958 
959   GVfsAfpReply *reply;
960   GError *err = NULL;
961   AfpResultCode res_code;
962 
963   reply = g_vfs_afp_connection_send_command_finish (conn, res, &err);
964   if (!reply)
965   {
966     g_task_return_error (task, err);
967     g_object_unref (task);
968     return;
969   }
970 
971   res_code = g_vfs_afp_reply_get_result_code (reply);
972   g_object_unref (reply);
973 
974   if (res_code != AFP_RESULT_NO_ERROR)
975   {
976     switch (res_code)
977     {
978       case AFP_RESULT_ACCESS_DENIED:
979         g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_PERMISSION_DENIED,
980                                  _("Permission denied"));
981         break;
982       case AFP_RESULT_DISK_FULL:
983         g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_NO_SPACE,
984                                  _("Not enough space on volume"));
985         break;
986       case AFP_RESULT_FLAT_VOL:
987         g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
988                                  /* Translators: flat means volume doesn't support directories
989                                     (all files are in the volume root) */
990                                  _("Volume is flat and doesn’t support directories"));
991         break;
992       case AFP_RESULT_OBJECT_NOT_FOUND:
993         g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_NOT_FOUND,
994                                  _("Ancestor directory doesn’t exist"));
995         break;
996       case AFP_RESULT_OBJECT_EXISTS:
997         g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_EXISTS,
998                                  _("Target directory already exists"));
999         break;
1000       case AFP_RESULT_VOL_LOCKED:
1001         g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_PERMISSION_DENIED,
1002                                  _("Volume is read-only"));
1003         break;
1004       default:
1005         g_task_return_error (task, afp_result_code_to_gerror (res_code));
1006         break;
1007     }
1008 
1009     g_object_unref (task);
1010     return;
1011   }
1012 
1013   g_task_return_boolean (task, TRUE);
1014   g_object_unref (task);
1015 }
1016 
1017 static void
create_directory_get_filedir_parms_cb(GObject * source_object,GAsyncResult * res,gpointer user_data)1018 create_directory_get_filedir_parms_cb (GObject *source_object, GAsyncResult *res, gpointer user_data)
1019 {
1020   GVfsAfpVolume *volume = G_VFS_AFP_VOLUME (source_object);
1021   GTask *task = G_TASK (user_data);
1022   CreateDirData *cdd = g_task_get_task_data (task);
1023 
1024   GFileInfo *info = NULL;
1025   GError *err = NULL;
1026 
1027   guint32 dir_id;
1028   GVfsAfpCommand *comm;
1029 
1030   info = g_vfs_afp_volume_get_filedir_parms_finish (volume, res, &err);
1031   if (!info)
1032   {
1033     g_task_return_error (task, err);
1034     g_object_unref (task);
1035     return;
1036   }
1037 
1038   dir_id = g_file_info_get_attribute_uint32 (info, G_FILE_ATTRIBUTE_AFP_NODE_ID);
1039   g_object_unref (info);
1040 
1041   comm = g_vfs_afp_command_new (AFP_COMMAND_CREATE_DIR);
1042   /* pad byte */
1043   g_vfs_afp_command_put_byte (comm, 0);
1044   /* Volume ID */
1045   g_vfs_afp_command_put_uint16 (comm, g_vfs_afp_volume_get_id (volume));
1046   /* Directory ID */
1047   g_vfs_afp_command_put_uint32 (comm, dir_id);
1048 
1049   /* Pathname */
1050   g_vfs_afp_command_put_pathname (comm, cdd->basename);
1051 
1052   g_vfs_afp_connection_send_command (volume->priv->conn, comm, NULL, make_directory_cb,
1053                                      g_task_get_cancellable (task), task);
1054   g_object_unref (comm);
1055 }
1056 
1057 /*
1058  * g_vfs_afp_volume_create_directory:
1059  *
1060  * @volume: a #GVfsAfpVolume.
1061  * @directory: path to the new directory to create.
1062  * @hard_create: if %TRUE this call will overwrite an already existing file.
1063  * If %FALSE it will error out instead.
1064  * @cancellable: optional #GCancellable object, %NULL to ignore.
1065  * @callback: callback to call when the request is satisfied.
1066  * @user_data: the data to pass to callback function.
1067  *
1068  * Asynchronously creates a directory at @directory.
1069  */
1070 void
g_vfs_afp_volume_create_directory(GVfsAfpVolume * volume,const char * directory,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)1071 g_vfs_afp_volume_create_directory (GVfsAfpVolume      *volume,
1072                                    const char         *directory,
1073                                    GCancellable       *cancellable,
1074                                    GAsyncReadyCallback callback,
1075                                    gpointer            user_data)
1076 {
1077   GTask *task;
1078   CreateDirData *cdd;
1079   char *dirname;
1080 
1081   g_return_if_fail (G_VFS_IS_AFP_VOLUME (volume));
1082 
1083   task = g_task_new (volume, cancellable, callback, user_data);
1084   g_task_set_source_tag (task, g_vfs_afp_volume_create_directory);
1085 
1086   cdd = g_slice_new (CreateDirData);
1087   cdd->basename = g_path_get_basename (directory);
1088 
1089   g_task_set_task_data (task, cdd, (GDestroyNotify)create_dir_data_free);
1090 
1091   dirname = g_path_get_dirname (directory);
1092   g_vfs_afp_volume_get_filedir_parms (volume, dirname, 0,
1093                                       AFP_DIR_BITMAP_NODE_ID_BIT,
1094                                       cancellable,
1095                                       create_directory_get_filedir_parms_cb,
1096                                       task);
1097   g_free (dirname);
1098 }
1099 
1100 /*
1101  * g_vfs_afp_volume_create_directory_finish:
1102  *
1103  * @volume: a #GVfsAfpVolume.
1104  * @result: a #GAsyncResult.
1105  * @error: a #GError, %NULL to ignore.
1106  *
1107  * Finalizes the asynchronous operation started by
1108  * g_vfs_afp_volume_create_directory.
1109  *
1110  * Returns: %TRUE on success, %FALSE on error.
1111  */
1112 gboolean
g_vfs_afp_volume_create_directory_finish(GVfsAfpVolume * volume,GAsyncResult * result,GError ** error)1113 g_vfs_afp_volume_create_directory_finish (GVfsAfpVolume  *volume,
1114                                           GAsyncResult   *result,
1115                                           GError         **error)
1116 {
1117   g_return_val_if_fail (g_task_is_valid (result, volume), FALSE);
1118   g_return_val_if_fail (g_async_result_is_tagged (result, g_vfs_afp_volume_create_directory), FALSE);
1119 
1120   return g_task_propagate_boolean (G_TASK (result), error);
1121 }
1122 
1123 typedef struct
1124 {
1125   char *filename;
1126   char *new_name;
1127 } RenameData;
1128 
1129 static void
rename_data_free(RenameData * rd)1130 rename_data_free (RenameData *rd)
1131 {
1132   g_free (rd->filename);
1133   g_free (rd->new_name);
1134   g_slice_free (RenameData, rd);
1135 }
1136 
1137 static void
rename_cb(GObject * source_object,GAsyncResult * res,gpointer user_data)1138 rename_cb (GObject *source_object, GAsyncResult *res, gpointer user_data)
1139 {
1140   GVfsAfpConnection *conn = G_VFS_AFP_CONNECTION (source_object);
1141   GTask *task = G_TASK (user_data);
1142 
1143   GVfsAfpReply *reply;
1144   GError *err = NULL;
1145   AfpResultCode res_code;
1146 
1147   reply = g_vfs_afp_connection_send_command_finish (conn, res, &err);
1148   if (!reply)
1149   {
1150     g_task_return_error (task, err);
1151     g_object_unref (task);
1152     return;
1153   }
1154 
1155   res_code = g_vfs_afp_reply_get_result_code (reply);
1156   g_object_unref (reply);
1157 
1158   if (res_code != AFP_RESULT_NO_ERROR)
1159   {
1160     switch (res_code)
1161     {
1162       case AFP_RESULT_ACCESS_DENIED:
1163         g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_PERMISSION_DENIED,
1164                                  _("Permission denied"));
1165         break;
1166       case AFP_RESULT_CANT_RENAME:
1167         g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_INVALID_FILENAME,
1168                                  _("Can’t rename volume"));
1169         break;
1170       case AFP_RESULT_OBJECT_EXISTS:
1171         g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_EXISTS,
1172                                  _("Object with that name already exists"));
1173         break;
1174       case AFP_RESULT_OBJECT_LOCKED:
1175         g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_FAILED,
1176                                  _("Target object is marked as not renameable (RenameInhibit)"));
1177         break;
1178       case AFP_RESULT_OBJECT_NOT_FOUND:
1179         g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_NOT_FOUND,
1180                                  _("Target object doesn’t exist"));
1181         break;
1182       case AFP_RESULT_VOL_LOCKED:
1183         g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_PERMISSION_DENIED,
1184                                  _("Volume is read-only"));
1185         break;
1186       default:
1187         g_task_return_error (task, afp_result_code_to_gerror (res_code));
1188         break;
1189     }
1190 
1191     g_object_unref (task);
1192     return;
1193   }
1194 
1195   g_task_return_boolean (task, TRUE);
1196   g_object_unref (task);
1197 }
1198 
1199 static void
rename_get_filedir_parms_cb(GObject * source_object,GAsyncResult * res,gpointer user_data)1200 rename_get_filedir_parms_cb (GObject      *source_object,
1201                              GAsyncResult *res,
1202                              gpointer      user_data)
1203 {
1204   GVfsAfpVolume *volume = G_VFS_AFP_VOLUME (source_object);
1205   GTask *task = G_TASK (user_data);
1206   RenameData *rd = g_task_get_task_data (task);
1207 
1208   GFileInfo *info;
1209   GError *err = NULL;
1210 
1211   guint32 dir_id;
1212   GVfsAfpCommand *comm;
1213   char *basename;
1214 
1215   info = g_vfs_afp_volume_get_filedir_parms_finish (volume, res, &err);
1216   if (!info)
1217   {
1218     g_task_return_error (task, err);
1219     g_object_unref (task);
1220     return;
1221   }
1222 
1223   dir_id = g_file_info_get_attribute_uint32 (info, G_FILE_ATTRIBUTE_AFP_PARENT_DIR_ID);
1224   g_object_unref (info);
1225 
1226   comm = g_vfs_afp_command_new (AFP_COMMAND_RENAME);
1227   /* pad byte */
1228   g_vfs_afp_command_put_byte (comm, 0);
1229   /* Volume ID */
1230   g_vfs_afp_command_put_uint16 (comm, g_vfs_afp_volume_get_id (volume));
1231   /* Directory ID */
1232   g_vfs_afp_command_put_uint32 (comm, dir_id);
1233 
1234   /* Pathname */
1235   basename = g_path_get_basename (rd->filename);
1236   g_vfs_afp_command_put_pathname (comm, basename);
1237   g_free (basename);
1238 
1239   /* NewName */
1240   g_vfs_afp_command_put_pathname (comm, rd->new_name);
1241 
1242   g_vfs_afp_connection_send_command (volume->priv->conn, comm, NULL, rename_cb,
1243                                      g_task_get_cancellable (task), task);
1244   g_object_unref (comm);
1245 }
1246 
1247 /*
1248  * g_vfs_afp_volume_rename:
1249  *
1250  * @volume: a #GVfsAfpVolume.
1251  * @filename: path to file to rename.
1252  * @new_name: the new name of the file.
1253  * @cancellable: optional #GCancellable object, %NULL to ignore.
1254  * @callback: callback to call when the request is satisfied.
1255  * @user_data: the data to pass to callback function.
1256  *
1257  * Asynchronously renames the file at @filename to @new_name.
1258  */
1259 void
g_vfs_afp_volume_rename(GVfsAfpVolume * volume,const char * filename,const char * new_name,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)1260 g_vfs_afp_volume_rename (GVfsAfpVolume      *volume,
1261                          const char         *filename,
1262                          const char         *new_name,
1263                          GCancellable       *cancellable,
1264                          GAsyncReadyCallback callback,
1265                          gpointer            user_data)
1266 {
1267   GTask *task;
1268   RenameData *rd;
1269 
1270   g_return_if_fail (G_VFS_IS_AFP_VOLUME (volume));
1271 
1272   task = g_task_new (volume, cancellable, callback, user_data);
1273   g_task_set_source_tag (task, g_vfs_afp_volume_rename);
1274 
1275   rd = g_slice_new (RenameData);
1276   rd->filename = g_strdup (filename);
1277   rd->new_name = g_strdup (new_name);
1278 
1279   g_task_set_task_data (task, rd, (GDestroyNotify)rename_data_free);
1280 
1281   g_vfs_afp_volume_get_filedir_parms (volume, filename,
1282                                       AFP_FILEDIR_BITMAP_PARENT_DIR_ID_BIT,
1283                                       AFP_FILEDIR_BITMAP_PARENT_DIR_ID_BIT,
1284                                       cancellable, rename_get_filedir_parms_cb,
1285                                       task);
1286 }
1287 
1288 /*
1289  * g_vfs_afp_volume_rename_finish:
1290  *
1291  * @volume: a #GVfsAfpVolume.
1292  * @result: a #GAsyncResult.
1293  * @error: a #GError, %NULL to ignore.
1294  *
1295  * Finalizes the asynchronous operation started by
1296  * g_vfs_afp_volume_move_and_rename.
1297  *
1298  * Returns: %TRUE on success, %FALSE on error.
1299  */
1300 gboolean
g_vfs_afp_volume_rename_finish(GVfsAfpVolume * volume,GAsyncResult * res,GError ** error)1301 g_vfs_afp_volume_rename_finish (GVfsAfpVolume  *volume,
1302                                 GAsyncResult   *res,
1303                                 GError        **error)
1304 {
1305   g_return_val_if_fail (g_task_is_valid (res, volume), FALSE);
1306   g_return_val_if_fail (g_async_result_is_tagged (res, g_vfs_afp_volume_rename), FALSE);
1307 
1308   return g_task_propagate_boolean (G_TASK (res), error);
1309 }
1310 
1311 static void
move_and_rename_cb(GObject * source_object,GAsyncResult * res,gpointer user_data)1312 move_and_rename_cb (GObject *source_object, GAsyncResult *res, gpointer user_data)
1313 {
1314   GVfsAfpConnection *conn = G_VFS_AFP_CONNECTION (source_object);
1315   GTask *task = G_TASK (user_data);
1316 
1317   GVfsAfpReply *reply;
1318   GError *err = NULL;
1319 
1320   AfpResultCode res_code;
1321 
1322   reply = g_vfs_afp_connection_send_command_finish (conn, res, &err);
1323   if (!reply)
1324   {
1325     g_task_return_error (task, err);
1326     g_object_unref (task);
1327     return;
1328   }
1329 
1330   res_code = g_vfs_afp_reply_get_result_code (reply);
1331   g_object_unref (reply);
1332 
1333   if (res_code != AFP_RESULT_NO_ERROR)
1334   {
1335     switch (res_code)
1336     {
1337       case AFP_RESULT_ACCESS_DENIED:
1338         g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_PERMISSION_DENIED,
1339                                  _("Permission denied"));
1340         break;
1341       case AFP_RESULT_CANT_MOVE:
1342         g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_WOULD_RECURSE,
1343                                  _("Can’t move directory into one of its descendants"));
1344         break;
1345       case AFP_RESULT_INSIDE_SHARE_ERR:
1346         g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_FAILED,
1347                                  _("Can’t move sharepoint into a shared directory"));
1348         break;
1349       case AFP_RESULT_INSIDE_TRASH_ERR:
1350         g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_FAILED,
1351                                  _("Can’t move a shared directory into the Trash"));
1352         break;
1353       case AFP_RESULT_OBJECT_EXISTS:
1354         g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_EXISTS,
1355                                  _("Target file already exists"));
1356         break;
1357       case AFP_RESULT_OBJECT_LOCKED:
1358         g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_NOT_FOUND,
1359                                  _("Object being moved is marked as not renameable (RenameInhibit)"));
1360         break;
1361       case AFP_RESULT_OBJECT_NOT_FOUND:
1362         g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_NOT_FOUND,
1363                                  _("Object being moved doesn’t exist"));
1364         break;
1365       default:
1366         g_task_return_error (task, afp_result_code_to_gerror (res_code));
1367         break;
1368     }
1369 
1370     g_object_unref (task);
1371     return;
1372   }
1373 
1374   g_task_return_boolean (task, TRUE);
1375   g_object_unref (task);
1376 }
1377 
1378 /*
1379  * g_vfs_afp_volume_move_and_rename:
1380  *
1381  * @volume: a #GVfsAfpVolume.
1382  * @source: the source path of the file to move.
1383  * @destination: destination path.
1384  * @cancellable: optional #GCancellable object, %NULL to ignore.
1385  * @callback: callback to call when the request is satisfied.
1386  * @user_data: the data to pass to callback function.
1387  *
1388  * Asynchronously moves (and renames) the file at @source to @destination.
1389  */
1390 void
g_vfs_afp_volume_move_and_rename(GVfsAfpVolume * volume,const char * source,const char * destination,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)1391 g_vfs_afp_volume_move_and_rename (GVfsAfpVolume      *volume,
1392                                   const char         *source,
1393                                   const char         *destination,
1394                                   GCancellable       *cancellable,
1395                                   GAsyncReadyCallback callback,
1396                                   gpointer            user_data)
1397 {
1398   GVfsAfpVolumePrivate *priv;
1399   GVfsAfpCommand *comm;
1400   char *dirname, *basename;
1401   GTask *task;
1402 
1403   g_return_if_fail (G_VFS_IS_AFP_VOLUME (volume));
1404 
1405   priv = volume->priv;
1406 
1407   comm = g_vfs_afp_command_new (AFP_COMMAND_MOVE_AND_RENAME);
1408   /* pad byte */
1409   g_vfs_afp_command_put_byte (comm, 0);
1410 
1411   /* VolumeID */
1412   g_vfs_afp_command_put_uint16 (comm, g_vfs_afp_volume_get_id (volume));
1413 
1414   /* SourceDirectoryID 2 == / */
1415   g_vfs_afp_command_put_uint32 (comm, 2);
1416   /* DestDirectoryID 2 == / */
1417   g_vfs_afp_command_put_uint32 (comm, 2);
1418 
1419   /* SourcePathname */
1420   g_vfs_afp_command_put_pathname (comm, source);
1421 
1422   /* DestPathname */
1423   dirname = g_path_get_dirname (destination);
1424   g_vfs_afp_command_put_pathname (comm, dirname);
1425   g_free (dirname);
1426 
1427   /* NewName */
1428   basename = g_path_get_basename (destination);
1429   g_vfs_afp_command_put_pathname (comm, basename);
1430   g_free (basename);
1431 
1432   task = g_task_new (volume, cancellable, callback, user_data);
1433   g_task_set_source_tag (task, g_vfs_afp_volume_move_and_rename);
1434 
1435   g_vfs_afp_connection_send_command (priv->conn, comm, NULL,
1436                                      move_and_rename_cb, cancellable, task);
1437   g_object_unref (comm);
1438 }
1439 
1440 /*
1441  * g_vfs_afp_volume_move_and_rename_finish:
1442  *
1443  * @volume: a #GVfsAfpVolume.
1444  * @result: a #GAsyncResult.
1445  * @error: a #GError, %NULL to ignore.
1446  *
1447  * Finalizes the asynchronous operation started by
1448  * g_vfs_afp_volume_move_and_rename.
1449  *
1450  * Returns: %TRUE on success, %FALSE on error.
1451  */
1452 gboolean
g_vfs_afp_volume_move_and_rename_finish(GVfsAfpVolume * volume,GAsyncResult * res,GError ** error)1453 g_vfs_afp_volume_move_and_rename_finish (GVfsAfpVolume  *volume,
1454                                          GAsyncResult   *res,
1455                                          GError        **error)
1456 {
1457   g_return_val_if_fail (g_task_is_valid (res, volume), FALSE);
1458   g_return_val_if_fail (g_async_result_is_tagged (res, g_vfs_afp_volume_move_and_rename), FALSE);
1459 
1460   return g_task_propagate_boolean (G_TASK (res), error);
1461 }
1462 
1463 static void
copy_file_cb(GObject * source_object,GAsyncResult * res,gpointer user_data)1464 copy_file_cb (GObject *source_object, GAsyncResult *res, gpointer user_data)
1465 {
1466   GVfsAfpConnection *conn = G_VFS_AFP_CONNECTION (source_object);
1467   GTask *task = G_TASK (user_data);
1468 
1469   GVfsAfpReply *reply;
1470   GError *err = NULL;
1471 
1472   AfpResultCode res_code;
1473 
1474   reply = g_vfs_afp_connection_send_command_finish (conn, res, &err);
1475   if (!reply)
1476   {
1477     g_task_return_error (task, err);
1478     g_object_unref (task);
1479     return;
1480   }
1481 
1482   res_code = g_vfs_afp_reply_get_result_code (reply);
1483   g_object_unref (reply);
1484 
1485   if (res_code != AFP_RESULT_NO_ERROR)
1486   {
1487     switch (res_code)
1488     {
1489       case AFP_RESULT_ACCESS_DENIED:
1490         g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_PERMISSION_DENIED,
1491                                  _("Permission denied"));
1492         break;
1493       case AFP_RESULT_CALL_NOT_SUPPORTED:
1494         g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
1495                                  _("Server doesn’t support the FPCopyFile operation"));
1496         break;
1497       case AFP_RESULT_DENY_CONFLICT:
1498         g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_FAILED,
1499                                  _("Unable to open source file for reading"));
1500         break;
1501       case AFP_RESULT_DISK_FULL:
1502         g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_NO_SPACE,
1503                                  _("Not enough space on volume"));
1504         break;
1505       case AFP_RESULT_OBJECT_EXISTS:
1506         g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_EXISTS,
1507                                  _("Target file already exists"));
1508         break;
1509       case AFP_RESULT_OBJECT_NOT_FOUND:
1510         g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_NOT_FOUND,
1511                                  _("Source file and/or destination directory doesn’t exist"));
1512         break;
1513       case AFP_RESULT_OBJECT_TYPE_ERR:
1514         g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_IS_DIRECTORY,
1515                                  _("Source file is a directory"));
1516         break;
1517       default:
1518         g_task_return_error (task, afp_result_code_to_gerror (res_code));
1519         break;
1520     }
1521 
1522     g_object_unref (task);
1523     return;
1524   }
1525 
1526   g_task_return_boolean (task, TRUE);
1527   g_object_unref (task);
1528 }
1529 
1530 /*
1531  * g_vfs_afp_volume_copy_file:
1532  *
1533  * @volume: a #GVfsAfpVolume.
1534  * @source: the source path of the file to copy.
1535  * @destination: destination path.
1536  * @cancellable: optional #GCancellable object, %NULL to ignore.
1537  * @callback: callback to call when the request is satisfied.
1538  * @user_data: the data to pass to callback function.
1539  *
1540  * Asynchronously copies the file at @source to @destination.
1541  */
1542 void
g_vfs_afp_volume_copy_file(GVfsAfpVolume * volume,const char * source,const char * destination,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)1543 g_vfs_afp_volume_copy_file (GVfsAfpVolume      *volume,
1544                             const char         *source,
1545                             const char         *destination,
1546                             GCancellable       *cancellable,
1547                             GAsyncReadyCallback callback,
1548                             gpointer            user_data)
1549 {
1550   GVfsAfpVolumePrivate *priv;
1551 
1552   GVfsAfpCommand *comm;
1553   char *dirname, *basename;
1554   GTask *task;
1555 
1556   g_return_if_fail (G_VFS_IS_AFP_VOLUME (volume));
1557 
1558   priv = volume->priv;
1559 
1560   comm = g_vfs_afp_command_new (AFP_COMMAND_COPY_FILE);
1561   /* pad byte */
1562   g_vfs_afp_command_put_byte (comm, 0);
1563 
1564   /* SourceVolumeID */
1565   g_vfs_afp_command_put_uint16 (comm, g_vfs_afp_volume_get_id (volume));
1566   /* SourceDirectoryID 2 == / */
1567   g_vfs_afp_command_put_uint32 (comm, 2);
1568 
1569   /* DestVolumeID */
1570   g_vfs_afp_command_put_uint16 (comm, g_vfs_afp_volume_get_id (volume));
1571   /* DestDirectoryID 2 == / */
1572   g_vfs_afp_command_put_uint32 (comm, 2);
1573 
1574   /* SourcePathname */
1575   g_vfs_afp_command_put_pathname (comm, source);
1576 
1577   /* DestPathname */
1578   dirname = g_path_get_dirname (destination);
1579   g_vfs_afp_command_put_pathname (comm, dirname);
1580   g_free (dirname);
1581 
1582   /* NewName */
1583   basename = g_path_get_basename (destination);
1584   g_vfs_afp_command_put_pathname (comm, basename);
1585   g_free (basename);
1586 
1587   task = g_task_new (volume, cancellable, callback, user_data);
1588   g_task_set_source_tag (task, g_vfs_afp_volume_copy_file);
1589 
1590   g_vfs_afp_connection_send_command (priv->conn, comm, NULL,
1591                                      copy_file_cb, cancellable, task);
1592   g_object_unref (comm);
1593 }
1594 
1595 /*
1596  * g_vfs_afp_volume_copy_file_finish:
1597  *
1598  * @volume: a #GVfsAfpVolume.
1599  * @result: a #GAsyncResult.
1600  * @error: a #GError, %NULL to ignore.
1601  *
1602  * Finalizes the asynchronous operation started by
1603  * g_vfs_afp_volume_copy_file.
1604  *
1605  * Returns: %TRUE on success, %FALSE on error.
1606  */
1607 gboolean
g_vfs_afp_volume_copy_file_finish(GVfsAfpVolume * volume,GAsyncResult * res,GError ** error)1608 g_vfs_afp_volume_copy_file_finish (GVfsAfpVolume *volume,
1609                                    GAsyncResult  *res,
1610                                    GError       **error)
1611 {
1612   g_return_val_if_fail (g_task_is_valid (res, volume), FALSE);
1613   g_return_val_if_fail (g_async_result_is_tagged (res, g_vfs_afp_volume_copy_file), FALSE);
1614 
1615   return g_task_propagate_boolean (G_TASK (res), error);
1616 }
1617 
1618 static void
get_filedir_parms_cb(GObject * source_object,GAsyncResult * result,gpointer user_data)1619 get_filedir_parms_cb (GObject *source_object, GAsyncResult *result, gpointer user_data)
1620 {
1621   GVfsAfpConnection *conn = G_VFS_AFP_CONNECTION (source_object);
1622   GTask *task = G_TASK (user_data);
1623   GVfsAfpVolume *volume = G_VFS_AFP_VOLUME (g_task_get_source_object (task));
1624 
1625   GVfsAfpReply *reply;
1626   GError *err = NULL;
1627   AfpResultCode res_code;
1628   gboolean res;
1629 
1630   guint16 file_bitmap, dir_bitmap, bitmap;
1631   guint8 FileDir;
1632   gboolean directory;
1633   GFileInfo *info;
1634 
1635   reply = g_vfs_afp_connection_send_command_finish (conn, result, &err);
1636   if (!reply)
1637   {
1638     g_task_return_error (task, err);
1639     g_object_unref (task);
1640     return;
1641   }
1642 
1643   res_code = g_vfs_afp_reply_get_result_code (reply);
1644   if (res_code != AFP_RESULT_NO_ERROR)
1645   {
1646     g_object_unref (reply);
1647 
1648     switch (res_code)
1649     {
1650       case AFP_RESULT_OBJECT_NOT_FOUND:
1651         g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_NOT_FOUND,
1652                                  _("File doesn’t exist"));
1653         break;
1654       default:
1655         g_task_return_error (task, afp_result_code_to_gerror (res_code));
1656         break;
1657     }
1658 
1659     g_object_unref (task);
1660     return;
1661   }
1662 
1663   g_vfs_afp_reply_read_uint16 (reply, &file_bitmap);
1664   g_vfs_afp_reply_read_uint16 (reply, &dir_bitmap);
1665 
1666   g_vfs_afp_reply_read_byte (reply, &FileDir);
1667   /* Pad Byte */
1668   g_vfs_afp_reply_read_byte (reply, NULL);
1669 
1670   directory = (FileDir & 0x80);
1671   bitmap =  directory ? dir_bitmap : file_bitmap;
1672 
1673   info = g_file_info_new ();
1674   res = g_vfs_afp_server_fill_info (volume->priv->server, info, reply, directory, bitmap, &err);
1675   g_object_unref (reply);
1676   if (!res)
1677   {
1678     g_task_return_error (task, err);
1679     g_object_unref (task);
1680     return;
1681   }
1682 
1683   g_task_return_pointer (task, info, g_object_unref);
1684   g_object_unref (task);
1685 }
1686 
1687 /*
1688  * g_vfs_afp_volume_get_filedir_parms:
1689  *
1690  * @volume: a #GVfsAfpVolume.
1691  * @filename: file or directory whose parameters should be retreived.
1692  * @file_bitmap: bitmap describing the parameters to retrieve if @filename is a
1693  * file.
1694  * @dir_bitmap: bitmap describing the parameters to retrieve if @filename is a
1695  * directory.
1696  * @cancellable: optional #GCancellable object, %NULL to ignore.
1697  * @callback: callback to call when the request is satisfied.
1698  * @user_data: the data to pass to callback function.
1699  *
1700  * Asynchronously retrieves the parameters described by @file_bitmap or
1701  * @dir_bitmap of the file/directory at @filename.
1702  */
1703 void
g_vfs_afp_volume_get_filedir_parms(GVfsAfpVolume * volume,const char * filename,guint16 file_bitmap,guint16 dir_bitmap,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)1704 g_vfs_afp_volume_get_filedir_parms (GVfsAfpVolume       *volume,
1705                                     const char          *filename,
1706                                     guint16              file_bitmap,
1707                                     guint16              dir_bitmap,
1708                                     GCancellable        *cancellable,
1709                                     GAsyncReadyCallback  callback,
1710                                     gpointer             user_data)
1711 {
1712   GVfsAfpVolumePrivate *priv;
1713   GVfsAfpCommand *comm;
1714   GTask *task;
1715 
1716   g_return_if_fail (G_VFS_IS_AFP_VOLUME (volume));
1717 
1718   priv = volume->priv;
1719 
1720   comm = g_vfs_afp_command_new (AFP_COMMAND_GET_FILE_DIR_PARMS);
1721   /* pad byte */
1722   g_vfs_afp_command_put_byte (comm, 0);
1723   /* VolumeID */
1724   g_vfs_afp_command_put_uint16 (comm, g_vfs_afp_volume_get_id (volume));
1725   /* Directory ID 2 == / */
1726   g_vfs_afp_command_put_uint32 (comm, 2);
1727   /* FileBitmap */
1728   g_vfs_afp_command_put_uint16 (comm, file_bitmap);
1729   /* DirectoryBitmap */
1730   g_vfs_afp_command_put_uint16 (comm, dir_bitmap);
1731   /* PathName */
1732   g_vfs_afp_command_put_pathname (comm, filename);
1733 
1734   task = g_task_new (volume, cancellable, callback, user_data);
1735   g_task_set_source_tag (task, g_vfs_afp_volume_get_filedir_parms);
1736 
1737   g_vfs_afp_connection_send_command (priv->conn, comm, NULL,
1738                                      get_filedir_parms_cb, cancellable,
1739                                      task);
1740   g_object_unref (comm);
1741 }
1742 
1743 /*
1744  * g_vfs_afp_volume_get_filedir_parms_finish:
1745  *
1746  * @volume: a #GVfsAfpVolume.
1747  * @result: a #GAsyncResult.
1748  * @error: a #GError, %NULL to ignore.
1749  *
1750  * Finalizes the asynchronous operation started by
1751  * g_vfs_afp_volume_get_fork_parms.
1752  *
1753  * Returns: (transfer full): A #GFileInfo with the requested parameters or %NULL
1754  * on error.
1755  */
1756 GFileInfo *
g_vfs_afp_volume_get_filedir_parms_finish(GVfsAfpVolume * volume,GAsyncResult * result,GError ** error)1757 g_vfs_afp_volume_get_filedir_parms_finish (GVfsAfpVolume  *volume,
1758                                            GAsyncResult   *result,
1759                                            GError         **error)
1760 {
1761   g_return_val_if_fail (g_task_is_valid (result, volume), NULL);
1762   g_return_val_if_fail (g_async_result_is_tagged (result, g_vfs_afp_volume_get_filedir_parms), NULL);
1763 
1764   return g_task_propagate_pointer (G_TASK (result), error);
1765 }
1766 
1767 static void
get_fork_parms_cb(GObject * source_object,GAsyncResult * result,gpointer user_data)1768 get_fork_parms_cb (GObject *source_object, GAsyncResult *result, gpointer user_data)
1769 {
1770   GVfsAfpConnection *conn = G_VFS_AFP_CONNECTION (source_object);
1771   GTask *task = G_TASK (user_data);
1772   GVfsAfpVolume *volume = G_VFS_AFP_VOLUME (g_task_get_source_object (task));
1773   GVfsAfpVolumePrivate *priv = volume->priv;
1774 
1775   GVfsAfpReply *reply;
1776   GError *err = NULL;
1777   AfpResultCode res_code;
1778   gboolean res;
1779 
1780   guint16 file_bitmap;
1781   GFileInfo *info;
1782 
1783   reply = g_vfs_afp_connection_send_command_finish (conn, result, &err);
1784   if (!reply)
1785   {
1786     g_task_return_error (task, err);
1787     g_object_unref (task);
1788     return;
1789   }
1790 
1791   res_code = g_vfs_afp_reply_get_result_code (reply);
1792   if (res_code != AFP_RESULT_NO_ERROR)
1793   {
1794     g_object_unref (reply);
1795 
1796     g_task_return_error (task, afp_result_code_to_gerror (res_code));
1797     g_object_unref (task);
1798     return;
1799   }
1800 
1801   g_vfs_afp_reply_read_uint16 (reply, &file_bitmap);
1802 
1803   info = g_file_info_new ();
1804   res = g_vfs_afp_server_fill_info (priv->server, info, reply, FALSE, file_bitmap, &err);
1805   g_object_unref (reply);
1806   if (!res)
1807   {
1808     g_task_return_error (task, err);
1809     g_object_unref (task);
1810     return;
1811   }
1812 
1813   g_task_return_pointer (task, info, g_object_unref);
1814   g_object_unref (task);
1815 }
1816 
1817 /*
1818  * g_vfs_afp_volume_get_fork_parms:
1819  *
1820  * @volume: a #GVfsAfpVolume.
1821  * @fork_refnume: the reference id of the fork.
1822  * @file_bitmap: bitmap describing the parameters to retrieve.
1823  * @cancellable: optional #GCancellable object, %NULL to ignore.
1824  * @callback: callback to call when the request is satisfied.
1825  * @user_data: the data to pass to callback function.
1826  *
1827  * Asynchronously retrieves the parameters described by @file_bitmap of the fork
1828  * with reference id @fork_refnum.
1829  */
1830 void
g_vfs_afp_volume_get_fork_parms(GVfsAfpVolume * volume,gint16 fork_refnum,guint16 file_bitmap,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)1831 g_vfs_afp_volume_get_fork_parms (GVfsAfpVolume       *volume,
1832                                  gint16               fork_refnum,
1833                                  guint16              file_bitmap,
1834                                  GCancellable        *cancellable,
1835                                  GAsyncReadyCallback  callback,
1836                                  gpointer             user_data)
1837 {
1838   GVfsAfpVolumePrivate *priv;
1839   GVfsAfpCommand *comm;
1840   GTask *task;
1841 
1842   g_return_if_fail (G_VFS_IS_AFP_VOLUME (volume));
1843 
1844   priv = volume->priv;
1845 
1846   comm = g_vfs_afp_command_new (AFP_COMMAND_GET_FORK_PARMS);
1847   /* pad byte */
1848   g_vfs_afp_command_put_byte (comm, 0);
1849   /* OForkRefNum */
1850   g_vfs_afp_command_put_int16 (comm, fork_refnum);
1851   /* Bitmap */
1852   g_vfs_afp_command_put_uint16 (comm, file_bitmap);
1853 
1854   task = g_task_new (volume, cancellable, callback, user_data);
1855   g_task_set_source_tag (task, g_vfs_afp_volume_get_fork_parms);
1856 
1857   g_vfs_afp_connection_send_command (priv->conn, comm, NULL,
1858                                      get_fork_parms_cb, cancellable,
1859                                      task);
1860   g_object_unref (comm);
1861 }
1862 
1863 /*
1864  * g_vfs_afp_volume_get_fork_parms_finish:
1865  *
1866  * @volume: a #GVfsAfpVolume.
1867  * @result: a #GAsyncResult.
1868  * @error: a #GError, %NULL to ignore.
1869  *
1870  * Finalizes the asynchronous operation started by
1871  * g_vfs_afp_volume_get_fork_parms.
1872  *
1873  * Returns: (transfer full): A #GFileInfo with the requested parameters or %NULL
1874  * on error.
1875  */
1876 GFileInfo *
g_vfs_afp_volume_get_fork_parms_finish(GVfsAfpVolume * volume,GAsyncResult * result,GError ** error)1877 g_vfs_afp_volume_get_fork_parms_finish (GVfsAfpVolume  *volume,
1878                                         GAsyncResult   *result,
1879                                         GError         **error)
1880 {
1881   g_return_val_if_fail (g_task_is_valid (result, volume), NULL);
1882   g_return_val_if_fail (g_async_result_is_tagged (result, g_vfs_afp_volume_get_fork_parms), NULL);
1883 
1884   return g_task_propagate_pointer (G_TASK (result), error);
1885 }
1886 
1887 static void
set_fork_parms_cb(GObject * source_object,GAsyncResult * res,gpointer user_data)1888 set_fork_parms_cb (GObject *source_object, GAsyncResult *res, gpointer user_data)
1889 {
1890   GVfsAfpConnection *conn = G_VFS_AFP_CONNECTION (source_object);
1891   GTask *task = G_TASK (user_data);
1892 
1893   GVfsAfpReply *reply;
1894   GError *err = NULL;
1895   AfpResultCode res_code;
1896 
1897   reply = g_vfs_afp_connection_send_command_finish (conn, res, &err);
1898   if (!reply)
1899   {
1900     g_task_return_error (task, err);
1901     g_object_unref (task);
1902     return;
1903   }
1904 
1905   res_code = g_vfs_afp_reply_get_result_code (reply);
1906   g_object_unref (reply);
1907   if (res_code != AFP_RESULT_NO_ERROR)
1908   {
1909     switch (res_code)
1910     {
1911       case AFP_RESULT_ACCESS_DENIED:
1912         g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_FAILED,
1913                                  _("Permission denied"));
1914         break;
1915       case AFP_RESULT_DISK_FULL:
1916         g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_NO_SPACE,
1917                                  _("Not enough space on volume"));
1918         break;
1919       case AFP_RESULT_LOCK_ERR:
1920         g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_FAILED,
1921                                  /* Translators: range conflict means
1922                                     requested data are locked by another user */
1923                                  _("Range lock conflict exists"));
1924         break;
1925       default:
1926         g_task_return_error (task, afp_result_code_to_gerror (res_code));
1927         break;
1928     }
1929 
1930     g_object_unref (task);
1931     return;
1932   }
1933 
1934   g_task_return_boolean (task, TRUE);
1935   g_object_unref (task);
1936 }
1937 
1938 /*
1939  * g_vfs_afp_volume_set_fork_size:
1940  *
1941  * @volume: a #GVfsAfpVolume.
1942  * @fork_refnume: the reference id of the fork.
1943  * @size: the new size of the fork,
1944  * @cancellable: optional #GCancellable object, %NULL to ignore.
1945  * @callback: callback to call when the request is satisfied.
1946  * @user_data: the data to pass to callback function.
1947  *
1948  * Asynchronously sets the size of the fork referenced by @fork_refnum.
1949  */
1950 void
g_vfs_afp_volume_set_fork_size(GVfsAfpVolume * volume,gint16 fork_refnum,gint64 size,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)1951 g_vfs_afp_volume_set_fork_size (GVfsAfpVolume       *volume,
1952                                 gint16               fork_refnum,
1953                                 gint64               size,
1954                                 GCancellable        *cancellable,
1955                                 GAsyncReadyCallback  callback,
1956                                 gpointer             user_data)
1957 {
1958   GVfsAfpVolumePrivate *priv;
1959   GVfsAfpCommand *comm;
1960   GTask *task;
1961 
1962   g_return_if_fail (G_VFS_IS_AFP_VOLUME (volume));
1963 
1964   priv = volume->priv;
1965 
1966   comm = g_vfs_afp_command_new (AFP_COMMAND_SET_FORK_PARMS);
1967   /* pad byte */
1968   g_vfs_afp_command_put_byte (comm, 0);
1969 
1970   /* OForkRefNum */
1971   g_vfs_afp_command_put_int16 (comm, fork_refnum);
1972   /* Bitmap */
1973   g_vfs_afp_command_put_uint16 (comm, AFP_FILE_BITMAP_EXT_DATA_FORK_LEN_BIT);
1974   /* ForkLen */
1975   g_vfs_afp_command_put_int64 (comm, size);
1976 
1977   task = g_task_new (volume, cancellable, callback, user_data);
1978   g_task_set_source_tag (task, g_vfs_afp_volume_set_fork_size);
1979 
1980   g_vfs_afp_connection_send_command (priv->conn, comm, NULL,
1981                                      set_fork_parms_cb, cancellable, task);
1982   g_object_unref (comm);
1983 }
1984 
1985 /*
1986  * g_vfs_afp_volume_set_fork_size_finish:
1987  *
1988  * @volume: a #GVfsAfpVolume.
1989  * @result: a #GAsyncResult.
1990  * @error: a #GError, %NULL to ignore.
1991  *
1992  * Finalizes the asynchronous operation started by
1993  * g_vfs_afp_volume_set_fork_size.
1994  *
1995  * Returns: (transfer full): %TRUE on success, %FALSE otherwise.
1996  */
1997 gboolean
g_vfs_afp_volume_set_fork_size_finish(GVfsAfpVolume * volume,GAsyncResult * result,GError ** error)1998 g_vfs_afp_volume_set_fork_size_finish (GVfsAfpVolume  *volume,
1999                                        GAsyncResult   *result,
2000                                        GError         **error)
2001 {
2002   g_return_val_if_fail (g_task_is_valid (result, volume), FALSE);
2003   g_return_val_if_fail (g_async_result_is_tagged (result, g_vfs_afp_volume_set_fork_size), FALSE);
2004 
2005   return g_task_propagate_boolean (G_TASK (result), error);
2006 }
2007 
2008 static void
set_unix_privs_cb(GObject * source_object,GAsyncResult * res,gpointer user_data)2009 set_unix_privs_cb (GObject *source_object, GAsyncResult *res, gpointer user_data)
2010 {
2011   GVfsAfpConnection *conn = G_VFS_AFP_CONNECTION (source_object);
2012   GTask *task = G_TASK (user_data);
2013 
2014   GVfsAfpReply *reply;
2015   GError *err = NULL;
2016   AfpResultCode res_code;
2017 
2018   reply = g_vfs_afp_connection_send_command_finish (conn, res, &err);
2019   if (!reply)
2020   {
2021     g_task_return_error (task, err);
2022     g_object_unref (task);
2023     return;
2024   }
2025 
2026   res_code = g_vfs_afp_reply_get_result_code (reply);
2027   g_object_unref (reply);
2028   if (res_code != AFP_RESULT_NO_ERROR)
2029   {
2030     switch (res_code)
2031     {
2032       case AFP_RESULT_ACCESS_DENIED:
2033         g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_PERMISSION_DENIED,
2034                                  _("Permission denied"));
2035         break;
2036       case AFP_RESULT_OBJECT_NOT_FOUND:
2037         g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_NOT_FOUND,
2038                                  _("Target object doesn’t exist"));
2039         break;
2040       case AFP_RESULT_VOL_LOCKED:
2041         g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_PERMISSION_DENIED,
2042                                  _("Volume is read-only"));
2043         break;
2044       default:
2045         g_task_return_error (task, afp_result_code_to_gerror (res_code));
2046         break;
2047     }
2048 
2049     g_object_unref (task);
2050     return;
2051   }
2052 
2053   g_task_return_boolean (task, TRUE);
2054   g_object_unref (task);
2055 }
2056 
2057 /*
2058  * g_vfs_afp_volume_set_unix_privs:
2059  *
2060  * @volume: a #GVfsAfpVolume.
2061  * @filename: file or directory whose unix privileges should be set.
2062  * @uid: the new user id of the file.
2063  * @gid: the new group id of the file.
2064  * @permissions: the new unix permissions of the file.
2065  * @ua_permissions: the new AFP access right of the file.
2066  * @cancellable: optional #GCancellable object, %NULL to ignore.
2067  * @callback: callback to call when the request is satisfied.
2068  * @user_data: the data to pass to callback function.
2069  *
2070  * Asynchronously sets new unix permissions on the file/directory pointed to by
2071  * @filename.
2072  */
2073 void
g_vfs_afp_volume_set_unix_privs(GVfsAfpVolume * volume,const char * filename,guint32 uid,guint32 gid,guint32 permissions,guint32 ua_permissions,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)2074 g_vfs_afp_volume_set_unix_privs (GVfsAfpVolume       *volume,
2075                                  const char          *filename,
2076                                  guint32              uid,
2077                                  guint32              gid,
2078                                  guint32              permissions,
2079                                  guint32              ua_permissions,
2080                                  GCancellable        *cancellable,
2081                                  GAsyncReadyCallback  callback,
2082                                  gpointer             user_data)
2083 {
2084   GVfsAfpVolumePrivate *priv;
2085   GVfsAfpCommand *comm;
2086   GTask *task;
2087 
2088   g_return_if_fail (G_VFS_IS_AFP_VOLUME (volume));
2089 
2090   priv = volume->priv;
2091 
2092   comm = g_vfs_afp_command_new (AFP_COMMAND_SET_FILEDIR_PARMS);
2093   /* pad byte */
2094   g_vfs_afp_command_put_byte (comm, 0);
2095 
2096   /* VolumeID */
2097   g_vfs_afp_command_put_uint16 (comm, g_vfs_afp_volume_get_id (volume));
2098   /* DirectoryID 2 == / */
2099   g_vfs_afp_command_put_uint32 (comm, 2);
2100   /* Bitmap */
2101   g_vfs_afp_command_put_uint16 (comm, AFP_FILEDIR_BITMAP_UNIX_PRIVS_BIT);
2102   /* Pathname */
2103   g_vfs_afp_command_put_pathname (comm, filename);
2104   /* pad to even */
2105   g_vfs_afp_command_pad_to_even (comm);
2106 
2107   /* UID */
2108   g_vfs_afp_command_put_uint32 (comm, uid);
2109   /* GID */
2110   g_vfs_afp_command_put_uint32 (comm, gid);
2111   /* Permissions */
2112   g_vfs_afp_command_put_uint32 (comm, permissions);
2113   /* UAPermissions */
2114   g_vfs_afp_command_put_uint32 (comm, ua_permissions);
2115 
2116   task = g_task_new (volume, cancellable, callback, user_data);
2117   g_task_set_source_tag (task, g_vfs_afp_volume_set_unix_privs);
2118 
2119   g_vfs_afp_connection_send_command (priv->conn, comm, NULL,
2120                                      set_unix_privs_cb, cancellable, task);
2121   g_object_unref (comm);
2122 }
2123 
2124 /*
2125  * g_vfs_afp_volume_set_unix_privs_finish:
2126  *
2127  * @volume: a #GVfsAfpVolume.
2128  * @result: a #GAsyncResult.
2129  * @error: a #GError, %NULL to ignore.
2130  *
2131  * Finalizes the asynchronous operation started by
2132  * g_vfs_afp_volume_set_unix_privs.
2133  *
2134  * Returns: %TRUE on success, %FALSE on error.
2135  */
2136 gboolean
g_vfs_afp_volume_set_unix_privs_finish(GVfsAfpVolume * volume,GAsyncResult * res,GError ** error)2137 g_vfs_afp_volume_set_unix_privs_finish (GVfsAfpVolume  *volume,
2138                                         GAsyncResult   *res,
2139                                         GError        **error)
2140 {
2141   g_return_val_if_fail (g_task_is_valid (res, volume), FALSE);
2142   g_return_val_if_fail (g_async_result_is_tagged (res, g_vfs_afp_volume_set_unix_privs), FALSE);
2143 
2144   return g_task_propagate_boolean (G_TASK (res), error);
2145 }
2146 
2147 static const gint16 ENUMERATE_REQ_COUNT           = G_MAXINT16;
2148 static const gint16 ENUMERATE_EXT_MAX_REPLY_SIZE  = G_MAXINT16;
2149 static const gint32 ENUMERATE_EXT2_MAX_REPLY_SIZE = G_MAXINT32;
2150 
2151 static void
enumerate_cb(GObject * source_object,GAsyncResult * res,gpointer user_data)2152 enumerate_cb (GObject *source_object, GAsyncResult *res, gpointer user_data)
2153 {
2154   GVfsAfpConnection *conn = G_VFS_AFP_CONNECTION (source_object);
2155   GTask *task = G_TASK (user_data);
2156   GVfsAfpVolume *volume = G_VFS_AFP_VOLUME (g_task_get_source_object (task));
2157   GVfsAfpVolumePrivate *priv = volume->priv;
2158 
2159   GVfsAfpReply *reply;
2160   GError *err = NULL;
2161   AfpResultCode res_code;
2162 
2163   guint16 file_bitmap;
2164   guint16  dir_bitmap;
2165   gint16 count, i;
2166   GPtrArray *infos;
2167 
2168   reply = g_vfs_afp_connection_send_command_finish (conn, res, &err);
2169   if (!reply)
2170   {
2171     g_task_return_error (task, err);
2172     g_object_unref (task);
2173     return;
2174   }
2175 
2176   res_code = g_vfs_afp_reply_get_result_code (reply);
2177   if (res_code != AFP_RESULT_NO_ERROR)
2178   {
2179     g_object_unref (reply);
2180 
2181     switch (res_code)
2182     {
2183       case AFP_RESULT_OBJECT_NOT_FOUND:
2184         g_task_return_pointer (task, NULL, NULL);
2185         break;
2186 
2187       case AFP_RESULT_ACCESS_DENIED:
2188         g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_PERMISSION_DENIED,
2189                                  _("Permission denied"));
2190         break;
2191       case AFP_RESULT_DIR_NOT_FOUND:
2192         g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_NOT_FOUND,
2193                                  _("Directory doesn’t exist"));
2194         break;
2195       case AFP_RESULT_OBJECT_TYPE_ERR:
2196         g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_NOT_DIRECTORY,
2197                                  _("Target object is not a directory"));
2198         break;
2199       default:
2200         g_task_return_error (task, afp_result_code_to_gerror (res_code));
2201         break;
2202     }
2203 
2204     g_object_unref (task);
2205     return;
2206   }
2207 
2208   g_vfs_afp_reply_read_uint16 (reply, &file_bitmap);
2209   g_vfs_afp_reply_read_uint16 (reply, &dir_bitmap);
2210 
2211   g_vfs_afp_reply_read_int16 (reply, &count);
2212   infos = g_ptr_array_new_full (count, g_object_unref);
2213 
2214   for (i = 0; i < count; i++)
2215   {
2216     goffset start_pos;
2217     guint16 struct_length;
2218     guint8 FileDir;
2219 
2220     gboolean directory;
2221     guint16 bitmap;
2222     GFileInfo *info;
2223 
2224     start_pos = g_vfs_afp_reply_get_pos (reply);
2225 
2226     g_vfs_afp_reply_read_uint16 (reply, &struct_length);
2227     g_vfs_afp_reply_read_byte (reply, &FileDir);
2228     /* pad byte */
2229     g_vfs_afp_reply_read_byte (reply, NULL);
2230 
2231     directory = (FileDir & 0x80);
2232     bitmap =  directory ? dir_bitmap : file_bitmap;
2233 
2234     info = g_file_info_new ();
2235     if (!g_vfs_afp_server_fill_info (priv->server, info, reply, directory, bitmap, &err))
2236     {
2237       g_object_unref (reply);
2238       g_task_return_error (task, err);
2239       g_object_unref (task);
2240       return;
2241     }
2242 
2243     g_ptr_array_add (infos, info);
2244 
2245     g_vfs_afp_reply_seek (reply, start_pos + struct_length, G_SEEK_SET);
2246   }
2247   g_object_unref (reply);
2248 
2249   g_task_return_pointer (task, infos, (GDestroyNotify)g_ptr_array_unref);
2250   g_object_unref (task);
2251 }
2252 
2253 /*
2254  * g_vfs_afp_volume_enumerate:
2255  *
2256  * @volume: a #GVfsAfpVolume.
2257  * @cancellable: optional #GCancellable object, %NULL to ignore.
2258  * @callback: callback to call when the request is satisfied.
2259  * @user_data: the data to pass to callback function.
2260  *
2261  * Asynchronously enumerates the files in @directory starting at index
2262  * @start_index.
2263  */
2264 void
g_vfs_afp_volume_enumerate(GVfsAfpVolume * volume,const char * directory,gint64 start_index,guint16 file_bitmap,guint16 dir_bitmap,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)2265 g_vfs_afp_volume_enumerate (GVfsAfpVolume       *volume,
2266                             const char          *directory,
2267                             gint64               start_index,
2268                             guint16              file_bitmap,
2269                             guint16              dir_bitmap,
2270                             GCancellable        *cancellable,
2271                             GAsyncReadyCallback  callback,
2272                             gpointer             user_data)
2273 {
2274   GVfsAfpVolumePrivate *priv;
2275 
2276   const GVfsAfpServerInfo *info;
2277   gint32 max;
2278 
2279   GVfsAfpCommand *comm;
2280   GTask *task;
2281 
2282   g_return_if_fail (G_VFS_IS_AFP_VOLUME (volume));
2283 
2284   priv = volume->priv;
2285 
2286   task = g_task_new (volume, cancellable, callback, user_data);
2287   g_task_set_source_tag (task, g_vfs_afp_volume_enumerate);
2288 
2289   info = g_vfs_afp_server_get_info (priv->server);
2290 
2291   max = (info->version >= AFP_VERSION_3_1) ? G_MAXINT32 : G_MAXINT16;
2292   /* Can't enumerate any more files */
2293   if (start_index > max)
2294   {
2295     g_task_return_pointer (task, NULL, NULL);
2296     g_object_unref (task);
2297     return;
2298   }
2299 
2300   if (info->version >= AFP_VERSION_3_1)
2301     comm = g_vfs_afp_command_new (AFP_COMMAND_ENUMERATE_EXT2);
2302   else
2303     comm = g_vfs_afp_command_new (AFP_COMMAND_ENUMERATE_EXT);
2304 
2305   /* pad byte */
2306   g_vfs_afp_command_put_byte (comm, 0);
2307 
2308   /* Volume ID */
2309   g_vfs_afp_command_put_uint16 (comm, g_vfs_afp_volume_get_id (volume));
2310   /* Directory ID 2 == / */
2311   g_vfs_afp_command_put_uint32 (comm, 2);
2312 
2313   /* File Bitmap */
2314   g_vfs_afp_command_put_uint16 (comm, file_bitmap);
2315 
2316   /* Dir Bitmap */
2317   g_vfs_afp_command_put_uint16 (comm, dir_bitmap);
2318 
2319   /* Req Count */
2320   g_vfs_afp_command_put_int16 (comm, ENUMERATE_REQ_COUNT);
2321 
2322 
2323   /* StartIndex and MaxReplySize */
2324   if (info->version >= AFP_VERSION_3_1)
2325   {
2326     g_vfs_afp_command_put_int32 (comm, start_index);
2327     g_vfs_afp_command_put_int32 (comm, ENUMERATE_EXT2_MAX_REPLY_SIZE);
2328   }
2329   else
2330   {
2331     g_vfs_afp_command_put_int16 (comm, start_index);
2332     g_vfs_afp_command_put_int16 (comm, ENUMERATE_EXT_MAX_REPLY_SIZE);
2333   }
2334 
2335   /* Pathname */
2336   g_vfs_afp_command_put_pathname (comm, directory);
2337 
2338   g_vfs_afp_connection_send_command (priv->conn, comm, NULL,
2339                                      enumerate_cb, cancellable, task);
2340   g_object_unref (comm);
2341 }
2342 
2343 /*
2344  * g_vfs_afp_volume_enumerate_finish:
2345  *
2346  * @volume: a #GVfsAfpVolume.
2347  * @result: a #GAsyncResult.
2348  * @infos: (out) (element-type G.FileInfo): array of #GFileInfo objects or %NULL
2349  * when no more files could be found.
2350  * @error: a #GError, %NULL to ignore.
2351  *
2352  * Finalizes the asynchronous operation started by
2353  * g_vfs_afp_volume_enumerate.
2354  *
2355  * Returns: %TRUE on success, %FALSE on error.
2356  */
2357 gboolean
g_vfs_afp_volume_enumerate_finish(GVfsAfpVolume * volume,GAsyncResult * res,GPtrArray ** infos,GError ** error)2358 g_vfs_afp_volume_enumerate_finish (GVfsAfpVolume  *volume,
2359                                    GAsyncResult   *res,
2360                                    GPtrArray      **infos,
2361                                    GError        **error)
2362 {
2363   g_return_val_if_fail (g_task_is_valid (res, volume), FALSE);
2364   g_return_val_if_fail (g_async_result_is_tagged (res, g_vfs_afp_volume_enumerate), FALSE);
2365 
2366   if (g_async_result_legacy_propagate_error (res, error))
2367     return FALSE;
2368 
2369   if (infos)
2370     *infos = g_task_propagate_pointer (G_TASK (res), NULL);
2371 
2372   return TRUE;
2373 }
2374 
2375 static void
close_replace_exchange_files_cb(GObject * source_object,GAsyncResult * res,gpointer user_data)2376 close_replace_exchange_files_cb (GObject *source_object, GAsyncResult *res, gpointer user_data)
2377 {
2378   GVfsAfpConnection *conn = G_VFS_AFP_CONNECTION (source_object);
2379   GTask *task = G_TASK (user_data);
2380 
2381   GVfsAfpReply *reply;
2382   GError *err = NULL;
2383   AfpResultCode res_code;
2384 
2385   reply = g_vfs_afp_connection_send_command_finish (conn, res, &err);
2386   if (!reply)
2387   {
2388     g_task_return_error (task, err);
2389     g_object_unref (task);
2390     return;
2391   }
2392 
2393   res_code = g_vfs_afp_reply_get_result_code (reply);
2394   g_object_unref (reply);
2395 
2396   if (res_code != AFP_RESULT_NO_ERROR)
2397   {
2398     switch (res_code)
2399     {
2400       case AFP_RESULT_ACCESS_DENIED:
2401         g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_FAILED,
2402                                  _("Permission denied"));
2403         break;
2404       case AFP_RESULT_ID_NOT_FOUND:
2405         g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_NOT_FOUND,
2406                                  _("File doesn’t exist"));
2407         break;
2408       case AFP_RESULT_OBJECT_TYPE_ERR:
2409         g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_IS_DIRECTORY,
2410                                  _("File is directory"));
2411         break;
2412       default:
2413         g_task_return_error (task, afp_result_code_to_gerror (res_code));
2414         break;
2415     }
2416 
2417     g_object_unref (task);
2418     return;
2419   }
2420 
2421   g_task_return_boolean (task, TRUE);
2422   g_object_unref (task);
2423 }
2424 
2425 /*
2426  * g_vfs_afp_volume_exchange_files:
2427  *
2428  * @volume: a #GVfsAfpVolume.
2429  * @source: path to source file to exchange.
2430  * @destination: path to destination file to exchange.
2431  * @cancellable: optional #GCancellable object, %NULL to ignore.
2432  * @callback: callback to call when the request is satisfied.
2433  * @user_data: the data to pass to callback function.
2434  *
2435  * Asynchronously exchanges the file system metadata of the two files @source
2436  * and @destination.
2437  */
2438 void
g_vfs_afp_volume_exchange_files(GVfsAfpVolume * volume,const char * source,const char * destination,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)2439 g_vfs_afp_volume_exchange_files (GVfsAfpVolume       *volume,
2440                                  const char          *source,
2441                                  const char          *destination,
2442                                  GCancellable        *cancellable,
2443                                  GAsyncReadyCallback  callback,
2444                                  gpointer             user_data)
2445 {
2446   GVfsAfpVolumePrivate *priv;
2447   GVfsAfpCommand *comm;
2448   GTask *task;
2449 
2450   g_return_if_fail (G_VFS_IS_AFP_VOLUME (volume));
2451 
2452   priv = volume->priv;
2453 
2454   comm = g_vfs_afp_command_new (AFP_COMMAND_EXCHANGE_FILES);
2455   /* pad byte */
2456   g_vfs_afp_command_put_byte (comm, 0);
2457 
2458   /* Volume ID */
2459   g_vfs_afp_command_put_uint16 (comm, g_vfs_afp_volume_get_id (volume));
2460   /* SourceDirectory ID 2 == / */
2461   g_vfs_afp_command_put_uint32 (comm, 2);
2462   /* DestDirectory ID 2 == / */
2463   g_vfs_afp_command_put_uint32 (comm, 2);
2464 
2465   /* SourcePath */
2466   g_vfs_afp_command_put_pathname (comm, source);
2467   /* DestPath */
2468   g_vfs_afp_command_put_pathname (comm, destination);
2469 
2470   task = g_task_new (volume, cancellable, callback, user_data);
2471   g_task_set_source_tag (task, g_vfs_afp_volume_exchange_files);
2472 
2473   g_vfs_afp_connection_send_command (priv->conn, comm, NULL,
2474                                      close_replace_exchange_files_cb,
2475                                      cancellable, task);
2476   g_object_unref (comm);
2477 }
2478 
2479 /*
2480  * g_vfs_afp_volume_exchange_files_finish:
2481  *
2482  * @volume: a #GVfsAfpVolume.
2483  * @result: a #GAsyncResult.
2484  * @error: a #GError, %NULL to ignore.
2485  *
2486  * Finalizes the asynchronous operation started by
2487  * g_vfs_afp_volume_exchange_files.
2488  *
2489  * Returns: %TRUE on success, %FALSE on error.
2490  */
2491 gboolean
g_vfs_afp_volume_exchange_files_finish(GVfsAfpVolume * volume,GAsyncResult * res,GError ** error)2492 g_vfs_afp_volume_exchange_files_finish (GVfsAfpVolume  *volume,
2493                                         GAsyncResult   *res,
2494                                         GError        **error)
2495 {
2496   g_return_val_if_fail (g_task_is_valid (res, volume), FALSE);
2497   g_return_val_if_fail (g_async_result_is_tagged (res, g_vfs_afp_volume_exchange_files), FALSE);
2498 
2499   return g_task_propagate_boolean (G_TASK (res), error);
2500 }
2501 
2502 static void
write_ext_cb(GObject * source_object,GAsyncResult * res,gpointer user_data)2503 write_ext_cb (GObject *source_object, GAsyncResult *res, gpointer user_data)
2504 {
2505   GVfsAfpConnection *conn = G_VFS_AFP_CONNECTION (source_object);
2506   GTask *task = G_TASK (user_data);
2507 
2508   GVfsAfpReply *reply;
2509   GError *err = NULL;
2510   AfpResultCode res_code;
2511   gint64 last_written;
2512 
2513   reply = g_vfs_afp_connection_send_command_finish (conn, res, &err);
2514   if (!reply)
2515   {
2516     g_task_return_error (task, err);
2517     g_object_unref (task);
2518     return;
2519   }
2520 
2521   res_code = g_vfs_afp_reply_get_result_code (reply);
2522   if (res_code != AFP_RESULT_NO_ERROR)
2523   {
2524     g_object_unref (reply);
2525 
2526     switch (res_code)
2527     {
2528       case AFP_RESULT_ACCESS_DENIED:
2529         g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_FAILED,
2530                                  _("File is not open for write access"));
2531         break;
2532       case AFP_RESULT_DISK_FULL:
2533         g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_NO_SPACE,
2534                                  _("Not enough space on volume"));
2535         break;
2536       case AFP_RESULT_LOCK_ERR:
2537         g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_FAILED,
2538                                  _("File is locked by another user"));
2539         break;
2540       default:
2541         g_task_return_error (task, afp_result_code_to_gerror (res_code));
2542         break;
2543     }
2544 
2545     g_object_unref (task);
2546     return;
2547   }
2548 
2549   g_vfs_afp_reply_read_int64 (reply, &last_written);
2550   g_object_unref (reply);
2551 
2552   g_task_return_int (task, last_written);
2553   g_object_unref (task);
2554 }
2555 
2556 /*
2557  * g_vfs_afp_volume_write_to_fork:
2558  *
2559  * @volume: a #GVfsAfpVolume.
2560  * @fork_refnume: reference id of the fork to write to.
2561  * @buffer: buffer containing the data to write. Must be valid during the whole
2562  * call.
2563  * @buffer_size: size of @buffer.
2564  * @offset: offset in file where the data should be written.
2565  * @cancellable: optional #GCancellable object, %NULL to ignore.
2566  * @callback: callback to call when the request is satisfied.
2567  * @user_data: the data to pass to callback function.
2568  *
2569  * Asynchronously writes the data in @buffer to the fork referenced by
2570  * @fork_refnum.
2571  */
2572 void
g_vfs_afp_volume_write_to_fork(GVfsAfpVolume * volume,guint16 fork_refnum,char * buffer,gsize buffer_size,gint64 offset,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)2573 g_vfs_afp_volume_write_to_fork (GVfsAfpVolume       *volume,
2574                                 guint16              fork_refnum,
2575                                 char                *buffer,
2576                                 gsize                buffer_size,
2577                                 gint64               offset,
2578                                 GCancellable        *cancellable,
2579                                 GAsyncReadyCallback  callback,
2580                                 gpointer             user_data)
2581 {
2582   GVfsAfpCommand *comm;
2583   guint32 req_count;
2584   GTask *task;
2585 
2586   g_return_if_fail (G_VFS_IS_AFP_VOLUME (volume));
2587 
2588   comm = g_vfs_afp_command_new (AFP_COMMAND_WRITE_EXT);
2589   /* StartEndFlag = 0 */
2590   g_vfs_afp_command_put_byte (comm, 0);
2591 
2592   /* OForkRefNum */
2593   g_vfs_afp_command_put_int16 (comm, fork_refnum);
2594   /* Offset */
2595   g_vfs_afp_command_put_int64 (comm, offset);
2596 
2597   /* ReqCount */
2598   req_count = MIN (buffer_size, G_MAXUINT32);
2599   g_vfs_afp_command_put_int64 (comm, req_count);
2600 
2601   g_vfs_afp_command_set_buffer (comm, buffer, req_count);
2602 
2603   task = g_task_new (volume, cancellable, callback, user_data);
2604   g_task_set_source_tag (task, g_vfs_afp_volume_write_to_fork);
2605 
2606   g_vfs_afp_connection_send_command (volume->priv->conn, comm, NULL,
2607                                      write_ext_cb, cancellable, task);
2608   g_object_unref (comm);
2609 }
2610 
2611 /*
2612  * g_vfs_afp_volume_write_to_fork_finish:
2613  *
2614  * @volume: a #GVfsAfpVolume.
2615  * @result: a #GAsyncResult.
2616  * @last_written: (out) (allow-none): offset of the last written byte.
2617  * @error: a #GError, %NULL to ignore.
2618  *
2619  * Finalizes the asynchronous operation started by
2620  * g_vfs_afp_volume_write_to_fork.
2621  *
2622  * Returns: %TRUE on success, %FALSE on error.
2623  */
2624 gboolean
g_vfs_afp_volume_write_to_fork_finish(GVfsAfpVolume * volume,GAsyncResult * res,gint64 * last_written,GError ** error)2625 g_vfs_afp_volume_write_to_fork_finish (GVfsAfpVolume  *volume,
2626                                        GAsyncResult   *res,
2627                                        gint64         *last_written,
2628                                        GError        **error)
2629 {
2630   g_return_val_if_fail (g_task_is_valid (res, volume), FALSE);
2631   g_return_val_if_fail (g_async_result_is_tagged (res, g_vfs_afp_volume_write_to_fork), FALSE);
2632 
2633   if (g_async_result_legacy_propagate_error (res, error))
2634     return FALSE;
2635 
2636   if (last_written)
2637     *last_written = g_task_propagate_int (G_TASK (res), NULL);
2638 
2639   return TRUE;
2640 }
2641 
2642 static void
read_ext_cb(GObject * source_object,GAsyncResult * res,gpointer user_data)2643 read_ext_cb (GObject *source_object, GAsyncResult *res, gpointer user_data)
2644 {
2645   GVfsAfpConnection *conn = G_VFS_AFP_CONNECTION (source_object);
2646   GTask *task = G_TASK (user_data);
2647 
2648   GVfsAfpReply *reply;
2649   GError *err = NULL;
2650   AfpResultCode res_code;
2651 
2652   reply = g_vfs_afp_connection_send_command_finish (conn, res, &err);
2653   if (!reply)
2654   {
2655     g_task_return_error (task, err);
2656     g_object_unref (task);
2657     return;
2658   }
2659 
2660   res_code = g_vfs_afp_reply_get_result_code (reply);
2661   if (!(res_code == AFP_RESULT_NO_ERROR || res_code == AFP_RESULT_LOCK_ERR ||
2662         res_code == AFP_RESULT_EOF_ERR))
2663   {
2664     g_object_unref (reply);
2665 
2666     switch (res_code)
2667     {
2668       case AFP_RESULT_ACCESS_DENIED:
2669         g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_FAILED,
2670                                   _("File is not open for read access"));
2671         break;
2672       default:
2673         g_task_return_error (task, afp_result_code_to_gerror (res_code));
2674         break;
2675     }
2676 
2677     g_object_unref (task);
2678     return;
2679   }
2680 
2681   g_task_return_int (task, g_vfs_afp_reply_get_size (reply));
2682   g_object_unref (task);
2683   g_object_unref (reply);
2684 }
2685 
2686 /*
2687  * g_vfs_afp_volume_read_from_fork:
2688  *
2689  * @volume: a #GVfsAfpVolume.
2690  * @fork_refnume: reference id of the fork to write to.
2691  * @buffer: buffer to read data into. Must be valid during the whole call.
2692  * @bytes_requested: number of bytes that should be read.
2693  * @offset: offset in file from where the data should be read.
2694  * @cancellable: optional #GCancellable object, %NULL to ignore.
2695  * @callback: callback to call when the request is satisfied.
2696  * @user_data: the data to pass to callback function.
2697  *
2698  * Asynchronously reads data from the fork referenced by @fork_refnum.
2699  */
2700 void
g_vfs_afp_volume_read_from_fork(GVfsAfpVolume * volume,guint16 fork_refnum,char * buffer,gsize bytes_requested,gint64 offset,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)2701 g_vfs_afp_volume_read_from_fork (GVfsAfpVolume       *volume,
2702                                  guint16              fork_refnum,
2703                                  char                *buffer,
2704                                  gsize                bytes_requested,
2705                                  gint64               offset,
2706                                  GCancellable        *cancellable,
2707                                  GAsyncReadyCallback  callback,
2708                                  gpointer             user_data)
2709 {
2710   GVfsAfpCommand *comm;
2711   guint32 req_count;
2712   GTask *task;
2713 
2714   g_return_if_fail (G_VFS_IS_AFP_VOLUME (volume));
2715 
2716   comm = g_vfs_afp_command_new (AFP_COMMAND_READ_EXT);
2717   /* pad byte */
2718   g_vfs_afp_command_put_byte (comm, 0);
2719 
2720   /* OForkRefNum */
2721   g_vfs_afp_command_put_int16 (comm, fork_refnum);
2722   /* Offset */
2723   g_vfs_afp_command_put_int64 (comm, offset);
2724   /* ReqCount */
2725   req_count = MIN (bytes_requested, G_MAXUINT32);
2726   g_vfs_afp_command_put_int64 (comm, req_count);
2727 
2728   task = g_task_new (volume, cancellable, callback, user_data);
2729   g_task_set_source_tag (task, g_vfs_afp_volume_read_from_fork);
2730 
2731   g_vfs_afp_connection_send_command (volume->priv->conn, comm, buffer,
2732                                      read_ext_cb, cancellable, task);
2733   g_object_unref (comm);
2734 }
2735 
2736 /*
2737  * g_vfs_afp_volume_read_from_fork_finish:
2738  *
2739  * @volume: a #GVfsAfpVolume.
2740  * @result: a #GAsyncResult.
2741  * @bytes_read: (out) (allow-none): the number of bytes that were read.
2742  * @error: a #GError, %NULL to ignore.
2743  *
2744  * Finalizes the asynchronous operation started by
2745  * g_vfs_afp_volume_read_from_fork.
2746  *
2747  * Returns: %TRUE on success, %FALSE on error.
2748  */
2749 gboolean
g_vfs_afp_volume_read_from_fork_finish(GVfsAfpVolume * volume,GAsyncResult * res,gsize * bytes_read,GError ** error)2750 g_vfs_afp_volume_read_from_fork_finish (GVfsAfpVolume  *volume,
2751                                         GAsyncResult   *res,
2752                                         gsize          *bytes_read,
2753                                         GError        **error)
2754 {
2755   g_return_val_if_fail (g_task_is_valid (res, volume), FALSE);
2756   g_return_val_if_fail (g_async_result_is_tagged (res, g_vfs_afp_volume_read_from_fork), FALSE);
2757 
2758   if (g_async_result_legacy_propagate_error (res, error))
2759     return FALSE;
2760 
2761   if (bytes_read)
2762     *bytes_read = g_task_propagate_int (G_TASK (res), NULL);
2763 
2764   return TRUE;
2765 }
2766 
2767 static void
attention_cb(GVfsAfpConnection * conn,guint attention,GVfsAfpVolume * volume)2768 attention_cb (GVfsAfpConnection *conn, guint attention, GVfsAfpVolume *volume)
2769 {
2770   /* Respond to the server notification with FPGetVolParms as the spec
2771    * suggests.  Some servers disconnect us if we don't. */
2772   if (attention == AFP_ATTENTION_CODE_SERVER_NOTIFICATION)
2773     g_vfs_afp_volume_get_parms (volume,
2774                                 AFP_VOLUME_BITMAP_VOL_ID_BIT,
2775                                 NULL, NULL, NULL);
2776 }
2777