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