1 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
2 *
3 * Copyright (C) 2007-2010 David Zeuthen <zeuthen@gmail.com>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18 *
19 */
20
21 #include "config.h"
22 #include <glib/gi18n-lib.h>
23
24 #include <sys/types.h>
25 #include <pwd.h>
26 #include <grp.h>
27 #include <string.h>
28 #include <stdlib.h>
29 #include <fcntl.h>
30 #include <sys/file.h>
31
32 #include <glib/gstdio.h>
33
34 #include <blockdev/part.h>
35 #include <blockdev/fs.h>
36
37 #include "udiskslogging.h"
38 #include "udiskslinuxpartitiontable.h"
39 #include "udiskslinuxblockobject.h"
40 #include "udisksdaemon.h"
41 #include "udisksdaemonutil.h"
42 #include "udiskslinuxdevice.h"
43 #include "udiskslinuxblock.h"
44 #include "udiskslinuxpartition.h"
45 #include "udiskssimplejob.h"
46
47 /**
48 * SECTION:udiskslinuxpartitiontable
49 * @title: UDisksLinuxPartitionTable
50 * @short_description: Linux implementation of #UDisksPartitionTable
51 *
52 * This type provides an implementation of the #UDisksPartitionTable
53 * interface on Linux.
54 */
55
56 typedef struct _UDisksLinuxPartitionTableClass UDisksLinuxPartitionTableClass;
57
58 /**
59 * UDisksLinuxPartitionTable:
60 *
61 * The #UDisksLinuxPartitionTable structure contains only private data and should
62 * only be accessed using the provided API.
63 */
64 struct _UDisksLinuxPartitionTable
65 {
66 UDisksPartitionTableSkeleton parent_instance;
67 };
68
69 struct _UDisksLinuxPartitionTableClass
70 {
71 UDisksPartitionTableSkeletonClass parent_class;
72 };
73
74 static void partition_table_iface_init (UDisksPartitionTableIface *iface);
75
76 G_DEFINE_TYPE_WITH_CODE (UDisksLinuxPartitionTable, udisks_linux_partition_table, UDISKS_TYPE_PARTITION_TABLE_SKELETON,
77 G_IMPLEMENT_INTERFACE (UDISKS_TYPE_PARTITION_TABLE, partition_table_iface_init));
78
79 /* ---------------------------------------------------------------------------------------------------- */
80
81 static void
udisks_linux_partition_table_init(UDisksLinuxPartitionTable * partition_table)82 udisks_linux_partition_table_init (UDisksLinuxPartitionTable *partition_table)
83 {
84 g_dbus_interface_skeleton_set_flags (G_DBUS_INTERFACE_SKELETON (partition_table),
85 G_DBUS_INTERFACE_SKELETON_FLAGS_HANDLE_METHOD_INVOCATIONS_IN_THREAD);
86 }
87
88 static void
udisks_linux_partition_table_class_init(UDisksLinuxPartitionTableClass * klass)89 udisks_linux_partition_table_class_init (UDisksLinuxPartitionTableClass *klass)
90 {
91 }
92
93 /**
94 * udisks_linux_partition_table_new:
95 *
96 * Creates a new #UDisksLinuxPartitionTable instance.
97 *
98 * Returns: A new #UDisksLinuxPartitionTable. Free with g_object_unref().
99 */
100 UDisksPartitionTable *
udisks_linux_partition_table_new(void)101 udisks_linux_partition_table_new (void)
102 {
103 return UDISKS_PARTITION_TABLE (g_object_new (UDISKS_TYPE_LINUX_PARTITION_TABLE,
104 NULL));
105 }
106
107 /* ---------------------------------------------------------------------------------------------------- */
108
109 /**
110 * udisks_linux_partition_table_update:
111 * @table: A #UDisksLinuxPartitionTable.
112 * @object: The enclosing #UDisksLinuxBlockObject instance.
113 *
114 * Updates the interface.
115 */
116 void
udisks_linux_partition_table_update(UDisksLinuxPartitionTable * table,UDisksLinuxBlockObject * object)117 udisks_linux_partition_table_update (UDisksLinuxPartitionTable *table,
118 UDisksLinuxBlockObject *object)
119 {
120 const gchar *type = NULL;
121 UDisksLinuxDevice *device = NULL;
122 UDisksDaemon *daemon = NULL;
123 guint num_parts = 0;
124 const gchar **partition_object_paths = NULL;
125 GList *partition_objects = NULL;
126 GList *object_p = NULL;
127 guint i = 0;
128
129 /* update partition table type */
130 device = udisks_linux_block_object_get_device (object);
131 if (device != NULL)
132 type = g_udev_device_get_property (device->udev_device, "ID_PART_TABLE_TYPE");
133
134 udisks_partition_table_set_type_ (UDISKS_PARTITION_TABLE (table), type);
135
136 /* update list of partitions */
137 daemon = udisks_linux_block_object_get_daemon (UDISKS_LINUX_BLOCK_OBJECT (object));
138
139 partition_objects = udisks_linux_partition_table_get_partitions (daemon, UDISKS_PARTITION_TABLE (table), &num_parts);
140
141 partition_object_paths = g_new0 (const gchar *, num_parts + 1);
142 for (i = 0, object_p = partition_objects; object_p != NULL; object_p = object_p->next, i++)
143 {
144 partition_object_paths[i] = g_dbus_object_get_object_path (g_dbus_interface_get_object (G_DBUS_INTERFACE (object_p->data)));
145 }
146
147 udisks_partition_table_set_partitions (UDISKS_PARTITION_TABLE (table),
148 partition_object_paths);
149 g_dbus_interface_skeleton_flush (G_DBUS_INTERFACE_SKELETON (table));
150
151
152 g_free (partition_object_paths);
153 g_clear_object (&device);
154 g_list_free_full (partition_objects, g_object_unref);
155 }
156
157 /* ---------------------------------------------------------------------------------------------------- */
158
159 GList *
udisks_linux_partition_table_get_partitions(UDisksDaemon * daemon,UDisksPartitionTable * table,guint * num_partitions)160 udisks_linux_partition_table_get_partitions (UDisksDaemon *daemon,
161 UDisksPartitionTable *table,
162 guint *num_partitions)
163 {
164 GList *ret = NULL;
165 GDBusObject *table_object;
166 const gchar *table_object_path;
167 GList *l, *object_proxies = NULL;
168 *num_partitions = 0;
169
170 table_object = g_dbus_interface_get_object (G_DBUS_INTERFACE (table));
171 if (table_object == NULL)
172 goto out;
173 table_object_path = g_dbus_object_get_object_path (table_object);
174
175 object_proxies = udisks_daemon_get_objects (daemon);
176 for (l = object_proxies; l != NULL; l = l->next)
177 {
178 UDisksObject *object = UDISKS_OBJECT (l->data);
179 UDisksPartition *partition;
180
181 partition = udisks_object_get_partition (object);
182 if (partition == NULL)
183 continue;
184
185 if (g_strcmp0 (udisks_partition_get_table (partition), table_object_path) == 0)
186 {
187 ret = g_list_prepend (ret, g_object_ref (partition));
188 (*num_partitions)++;
189 }
190
191 g_object_unref (partition);
192 }
193 ret = g_list_reverse (ret);
194 out:
195 g_list_free_full (object_proxies, g_object_unref);
196 return ret;
197 }
198
199 /* ---------------------------------------------------------------------------------------------------- */
200
201 typedef struct
202 {
203 UDisksObject *partition_table_object;
204 guint64 pos_to_wait_for;
205 gboolean ignore_container;
206 } WaitForPartitionData;
207
208 static UDisksObject *
wait_for_partition(UDisksDaemon * daemon,gpointer user_data)209 wait_for_partition (UDisksDaemon *daemon,
210 gpointer user_data)
211 {
212 WaitForPartitionData *data = user_data;
213 UDisksObject *ret = NULL;
214 GList *objects, *l;
215
216 objects = udisks_daemon_get_objects (daemon);
217 for (l = objects; l != NULL; l = l->next)
218 {
219 UDisksObject *object = UDISKS_OBJECT (l->data);
220 UDisksPartition *partition = udisks_object_get_partition (object);
221 if (partition != NULL)
222 {
223 if (g_strcmp0 (udisks_partition_get_table (partition),
224 g_dbus_object_get_object_path (G_DBUS_OBJECT (data->partition_table_object))) == 0)
225 {
226 guint64 offset = udisks_partition_get_offset (partition);
227 guint64 size = udisks_partition_get_size (partition);
228
229 if (data->pos_to_wait_for >= offset && data->pos_to_wait_for < offset + size)
230 {
231 if (!(udisks_partition_get_is_container (partition) && data->ignore_container))
232 {
233 g_object_unref (partition);
234 ret = g_object_ref (object);
235 goto out;
236 }
237 }
238 }
239 g_object_unref (partition);
240 }
241 }
242
243 out:
244 g_list_free_full (objects, g_object_unref);
245 return ret;
246 }
247
248 #define MIB_SIZE (1048576L)
249
250 static UDisksObject *
udisks_linux_partition_table_handle_create_partition(UDisksPartitionTable * table,GDBusMethodInvocation * invocation,guint64 offset,guint64 size,const gchar * type,const gchar * name,GVariant * options)251 udisks_linux_partition_table_handle_create_partition (UDisksPartitionTable *table,
252 GDBusMethodInvocation *invocation,
253 guint64 offset,
254 guint64 size,
255 const gchar *type,
256 const gchar *name,
257 GVariant *options)
258 {
259 const gchar *action_id = NULL;
260 const gchar *message = NULL;
261 UDisksBlock *block = NULL;
262 UDisksObject *object = NULL;
263 UDisksDaemon *daemon = NULL;
264 gchar *device_name = NULL;
265 WaitForPartitionData *wait_data = NULL;
266 UDisksObject *partition_object = NULL;
267 UDisksBlock *partition_block = NULL;
268 BDPartSpec *part_spec = NULL;
269 BDPartSpec *overlapping_part = NULL;
270 BDPartTypeReq part_type = 0;
271 gchar *table_type = NULL;
272 uid_t caller_uid;
273 GError *error = NULL;
274 UDisksBaseJob *job = NULL;
275 const gchar *partition_type = NULL;
276
277 object = udisks_daemon_util_dup_object (table, &error);
278 if (object == NULL)
279 {
280 g_dbus_method_invocation_take_error (invocation, error);
281 goto out;
282 }
283
284 daemon = udisks_linux_block_object_get_daemon (UDISKS_LINUX_BLOCK_OBJECT (object));
285
286 g_variant_lookup (options, "partition-type", "&s", &partition_type);
287
288 block = udisks_object_get_block (object);
289 if (block == NULL)
290 {
291 g_dbus_method_invocation_return_error (invocation, UDISKS_ERROR, UDISKS_ERROR_FAILED,
292 "Partition table object is not a block device");
293 goto out;
294 }
295
296 error = NULL;
297 if (!udisks_daemon_util_get_caller_uid_sync (daemon,
298 invocation,
299 NULL /* GCancellable */,
300 &caller_uid,
301 &error))
302 {
303 g_dbus_method_invocation_return_gerror (invocation, error);
304 g_clear_error (&error);
305 goto out;
306 }
307
308 action_id = "org.freedesktop.udisks2.modify-device";
309 /* Translators: Shown in authentication dialog when the user
310 * requests creating a new partition.
311 *
312 * Do not translate $(drive), it's a placeholder and
313 * will be replaced by the name of the drive/device in question
314 */
315 message = N_("Authentication is required to create a partition on $(drive)");
316 if (!udisks_daemon_util_setup_by_user (daemon, object, caller_uid))
317 {
318 if (udisks_block_get_hint_system (block))
319 {
320 action_id = "org.freedesktop.udisks2.modify-device-system";
321 }
322 else if (!udisks_daemon_util_on_user_seat (daemon, object, caller_uid))
323 {
324 action_id = "org.freedesktop.udisks2.modify-device-other-seat";
325 }
326 }
327
328 if (!udisks_daemon_util_check_authorization_sync (daemon,
329 object,
330 action_id,
331 options,
332 message,
333 invocation))
334 goto out;
335
336 device_name = g_strdup (udisks_block_get_device (block));
337
338 table_type = udisks_partition_table_dup_type_ (table);
339 wait_data = g_new0 (WaitForPartitionData, 1);
340 if (g_strcmp0 (table_type, "dos") == 0)
341 {
342 char *endp;
343 gint type_as_int;
344
345 if (strlen (name) > 0)
346 {
347 g_dbus_method_invocation_return_error (invocation, UDISKS_ERROR, UDISKS_ERROR_FAILED,
348 "MBR partition table does not support names");
349 goto out;
350 }
351
352 type_as_int = strtol (type, &endp, 0);
353
354 /* Determine whether we are creating a primary, extended or logical partition */
355 if (partition_type != NULL)
356 {
357 if (g_strcmp0 (partition_type, "primary") == 0)
358 {
359 part_type = BD_PART_TYPE_REQ_NORMAL;
360 }
361 else if (g_strcmp0 (partition_type, "extended") == 0)
362 {
363 part_type = BD_PART_TYPE_REQ_EXTENDED;
364 }
365 else if (g_strcmp0 (partition_type, "logical") == 0)
366 {
367 part_type = BD_PART_TYPE_REQ_LOGICAL;
368 }
369 else
370 {
371 g_dbus_method_invocation_return_error (invocation, UDISKS_ERROR, UDISKS_ERROR_FAILED,
372 "Don't know how to create partition of type `%s'",
373 partition_type);
374 goto out;
375 }
376 }
377 else if (type[0] != '\0' && *endp == '\0' &&
378 (type_as_int == 0x05 || type_as_int == 0x0f || type_as_int == 0x85))
379 {
380 part_type = BD_PART_TYPE_REQ_EXTENDED;
381 }
382 else
383 part_type = BD_PART_TYPE_REQ_NEXT;
384 }
385 else if (g_strcmp0 (table_type, "gpt") == 0)
386 {
387 part_type = BD_PART_TYPE_REQ_NORMAL;
388 }
389 else
390 {
391 g_dbus_method_invocation_return_error (invocation, UDISKS_ERROR, UDISKS_ERROR_FAILED,
392 "Don't know how to create partitions this partition table of type `%s'",
393 table_type);
394 goto out;
395 }
396
397 job = udisks_daemon_launch_simple_job (daemon,
398 UDISKS_OBJECT (object),
399 "partition-create",
400 caller_uid,
401 NULL);
402
403 if (job == NULL)
404 {
405 g_dbus_method_invocation_return_error (invocation, UDISKS_ERROR, UDISKS_ERROR_FAILED,
406 "Failed to create a job object");
407 goto out;
408 }
409
410 /* Users might want to specify logical partitions start and size using size of
411 * of the extended partition. If this happens we need to shift start (offset)
412 * of the logical partition.
413 * XXX: We really shouldn't allow creation of overlapping partitions and
414 * and just automatically fix this. But udisks currently doesn't have
415 * functions to get free regions on the disks so this is a somewhat valid
416 * use case. But we should definitely provide some functionality to get
417 * right "numbers" and stop doing this.
418 */
419 overlapping_part = bd_part_get_part_by_pos (device_name, offset, &error);
420 if (overlapping_part != NULL && ! (overlapping_part->type & BD_PART_TYPE_FREESPACE))
421 {
422 /* extended partition or metadata of the extended partition */
423 if (overlapping_part->type & BD_PART_TYPE_EXTENDED || overlapping_part->type & (BD_PART_TYPE_LOGICAL | BD_PART_TYPE_METADATA))
424 {
425 if (overlapping_part->start == offset)
426 {
427 /* just add 1 byte, libblockdev will adjust it */
428 offset += 1;
429 udisks_warning ("Requested start of the logical partition overlaps "
430 "with extended partition metadata. Start of the "
431 "partition moved to %"G_GUINT64_FORMAT".", offset);
432 }
433 }
434 else
435 {
436 /* overlapping partition is not a free space nor an extended part -> error */
437 g_dbus_method_invocation_return_error (invocation, UDISKS_ERROR, UDISKS_ERROR_FAILED,
438 "Requested start for the new partition %"G_GUINT64_FORMAT" "
439 "overlaps with existing partition %s.",
440 offset, overlapping_part->path);
441 goto out;
442 }
443 }
444 else
445 g_clear_error (&error);
446
447 part_spec = bd_part_create_part (device_name, part_type, offset,
448 size, BD_PART_ALIGN_OPTIMAL, &error);
449 if (!part_spec)
450 {
451 g_dbus_method_invocation_return_error (invocation,
452 UDISKS_ERROR,
453 UDISKS_ERROR_FAILED,
454 "Error creating partition on %s: %s",
455 udisks_block_get_device (block),
456 error->message);
457 udisks_simple_job_complete (UDISKS_SIMPLE_JOB (job), FALSE, error->message);
458 goto out;
459 }
460
461 /* set name if given */
462 if (g_strcmp0 (table_type, "gpt") == 0 && strlen (name) > 0)
463 {
464 if (!bd_part_set_part_name (device_name, part_spec->path, name, &error))
465 {
466 g_prefix_error (&error, "Error setting name for newly created partition: ");
467 g_dbus_method_invocation_take_error (invocation, error);
468 udisks_simple_job_complete (UDISKS_SIMPLE_JOB (job), FALSE, error->message);
469 goto out;
470 }
471 }
472
473 /* set type if given and if not extended partition */
474 if (part_spec->type != BD_PART_TYPE_EXTENDED && strlen (type) > 0)
475 {
476 gboolean ret = FALSE;
477
478 if (g_strcmp0 (table_type, "gpt") == 0)
479 ret = bd_part_set_part_type (device_name, part_spec->path, type, &error);
480 else if (g_strcmp0 (table_type, "dos") == 0)
481 ret = bd_part_set_part_id (device_name, part_spec->path, type, &error);
482
483 if (!ret)
484 {
485 g_prefix_error (&error, "Error setting type for newly created partition: ");
486 g_dbus_method_invocation_take_error (invocation, error);
487 udisks_simple_job_complete (UDISKS_SIMPLE_JOB (job), FALSE, error->message);
488 goto out;
489 }
490 }
491
492 /* wipe the newly created partition if wanted */
493 if (part_spec->type != BD_PART_TYPE_EXTENDED)
494 {
495 if (!bd_fs_wipe (part_spec->path, TRUE, &error))
496 {
497 if (g_error_matches (error, BD_FS_ERROR, BD_FS_ERROR_NOFS))
498 g_clear_error (&error);
499 else
500 {
501 g_dbus_method_invocation_return_error (invocation,
502 UDISKS_ERROR,
503 UDISKS_ERROR_FAILED,
504 "Error wiping newly created partition %s: %s",
505 part_spec->path,
506 error->message);
507 udisks_simple_job_complete (UDISKS_SIMPLE_JOB (job), FALSE, error->message);
508 goto out;
509 }
510 }
511 }
512
513 wait_data->ignore_container = (part_spec->type == BD_PART_TYPE_LOGICAL);
514 wait_data->pos_to_wait_for = part_spec->start + (part_spec->size / 2L);
515
516 /* sit and wait for the partition to show up */
517 g_warn_if_fail (wait_data->pos_to_wait_for > 0);
518 wait_data->partition_table_object = object;
519 error = NULL;
520 partition_object = udisks_daemon_wait_for_object_sync (daemon,
521 wait_for_partition,
522 wait_data,
523 NULL,
524 UDISKS_DEFAULT_WAIT_TIMEOUT,
525 &error);
526 if (partition_object == NULL)
527 {
528 g_prefix_error (&error, "Error waiting for partition to appear: ");
529 g_dbus_method_invocation_take_error (invocation, error);
530 udisks_simple_job_complete (UDISKS_SIMPLE_JOB (job), FALSE, error->message);
531 goto out;
532 }
533 partition_block = udisks_object_get_block (partition_object);
534 if (partition_block == NULL)
535 {
536 g_dbus_method_invocation_return_error (invocation, UDISKS_ERROR, UDISKS_ERROR_FAILED,
537 "Partition object is not a block device");
538 g_clear_object (&partition_object);
539 udisks_simple_job_complete (UDISKS_SIMPLE_JOB (job), FALSE, NULL);
540 goto out;
541 }
542
543 /* Trigger uevent on the disk -- we sometimes get add-remove-add uevents for
544 the new partition without getting change event for the disks after the
545 last add event and this breaks the "Partitions" property on the
546 "PartitionTable" interface. */
547 udisks_linux_block_object_trigger_uevent_sync (UDISKS_LINUX_BLOCK_OBJECT (object),
548 UDISKS_DEFAULT_WAIT_TIMEOUT);
549
550 udisks_simple_job_complete (UDISKS_SIMPLE_JOB (job), TRUE, NULL);
551
552 out:
553 g_free (table_type);
554 g_free (wait_data);
555 g_clear_error (&error);
556 g_clear_object (&partition_block);
557 g_free (device_name);
558 g_clear_object (&object);
559 g_clear_object (&block);
560 if (part_spec)
561 bd_part_spec_free (part_spec);
562 if (overlapping_part)
563 bd_part_spec_free (overlapping_part);
564 return partition_object;
565 }
566
567 static int
flock_block_dev(UDisksPartitionTable * iface)568 flock_block_dev (UDisksPartitionTable *iface)
569 {
570 UDisksObject *object = udisks_daemon_util_dup_object (iface, NULL);
571 UDisksBlock *block = object? udisks_object_peek_block (object) : NULL;
572 int fd = block? open (udisks_block_get_device (block), O_RDONLY) : -1;
573
574 if (fd >= 0)
575 flock (fd, LOCK_SH | LOCK_NB);
576
577 g_clear_object (&object);
578 return fd;
579 }
580
581 static void
unflock_block_dev(int fd)582 unflock_block_dev (int fd)
583 {
584 if (fd >= 0)
585 close (fd);
586 }
587
588 /* runs in thread dedicated to handling @invocation */
589 static gboolean
handle_create_partition(UDisksPartitionTable * table,GDBusMethodInvocation * invocation,guint64 offset,guint64 size,const gchar * type,const gchar * name,GVariant * options)590 handle_create_partition (UDisksPartitionTable *table,
591 GDBusMethodInvocation *invocation,
592 guint64 offset,
593 guint64 size,
594 const gchar *type,
595 const gchar *name,
596 GVariant *options)
597 {
598 /* We (try to) take a shared lock on the partition table while
599 creating and formatting a new partition, here and also in
600 handle_create_partition_and_format.
601
602 This lock prevents udevd from issuing a BLKRRPART ioctl call.
603 That ioctl is undesired because it might temporarily remove the
604 block device of the newly created block device. It does so only
605 temporarily, but it still happens that the block device is
606 missing exactly when wipefs or mkfs try to access it.
607
608 Also, a pair of remove/add events will cause udisks to create a
609 new internal UDisksObject to represent the block device of the
610 partition. The code currently doesn't handle this and waits for
611 changes (such as an expected filesystem type or UUID) to a
612 obsolete internal object that will never see them.
613 */
614
615 int fd = flock_block_dev (table);
616 UDisksObject *partition_object =
617 udisks_linux_partition_table_handle_create_partition (table,
618 invocation,
619 offset,
620 size,
621 type,
622 name,
623 options);
624
625 if (partition_object)
626 {
627 udisks_partition_table_complete_create_partition
628 (table, invocation, g_dbus_object_get_object_path (G_DBUS_OBJECT (partition_object)));
629 g_object_unref (partition_object);
630 }
631
632 unflock_block_dev (fd);
633
634 return TRUE; /* returning TRUE means that we handled the method invocation */
635 }
636
637 /* runs in thread dedicated to handling @invocation */
638 struct FormatCompleteData {
639 UDisksPartitionTable *table;
640 GDBusMethodInvocation *invocation;
641 UDisksObject *partition_object;
642 int lock_fd;
643 };
644
645 static void
handle_format_complete(gpointer user_data)646 handle_format_complete (gpointer user_data)
647 {
648 struct FormatCompleteData *data = user_data;
649 udisks_partition_table_complete_create_partition
650 (data->table, data->invocation, g_dbus_object_get_object_path (G_DBUS_OBJECT (data->partition_object)));
651 unflock_block_dev (data->lock_fd);
652 }
653
654 static gboolean
handle_create_partition_and_format(UDisksPartitionTable * table,GDBusMethodInvocation * invocation,guint64 offset,guint64 size,const gchar * type,const gchar * name,GVariant * options,const gchar * format_type,GVariant * format_options)655 handle_create_partition_and_format (UDisksPartitionTable *table,
656 GDBusMethodInvocation *invocation,
657 guint64 offset,
658 guint64 size,
659 const gchar *type,
660 const gchar *name,
661 GVariant *options,
662 const gchar *format_type,
663 GVariant *format_options)
664 {
665 /* See handle_create_partition for a motivation of taking the lock.
666 */
667
668 int fd = flock_block_dev (table);
669 UDisksObject *partition_object =
670 udisks_linux_partition_table_handle_create_partition (table,
671 invocation,
672 offset,
673 size,
674 type,
675 name,
676 options);
677
678 if (partition_object)
679 {
680 struct FormatCompleteData data;
681 data.table = table;
682 data.invocation = invocation;
683 data.partition_object = partition_object;
684 data.lock_fd = fd;
685 udisks_linux_block_handle_format (udisks_object_peek_block (partition_object),
686 invocation,
687 format_type,
688 format_options,
689 handle_format_complete, &data);
690 g_object_unref (partition_object);
691 }
692 else
693 unflock_block_dev (fd);
694
695 return TRUE; /* returning TRUE means that we handled the method invocation */
696 }
697
698 /* ---------------------------------------------------------------------------------------------------- */
699
700 static void
partition_table_iface_init(UDisksPartitionTableIface * iface)701 partition_table_iface_init (UDisksPartitionTableIface *iface)
702 {
703 iface->handle_create_partition = handle_create_partition;
704 iface->handle_create_partition_and_format = handle_create_partition_and_format;
705 }
706