LCOV - code coverage report
Current view: top level - plugins/fs - udf.c (source / functions) Coverage Total Hit
Test: libblockdev Coverage Report Lines: 76.2 % 240 183
Test Date: 2026-01-26 13:19:28 Functions: 85.7 % 14 12
Legend: Lines: hit not hit

            Line data    Source code
       1              : /*
       2              :  * Copyright (C) 2020  Red Hat, Inc.
       3              :  *
       4              :  * This library is free software; you can redistribute it and/or
       5              :  * modify it under the terms of the GNU Lesser General Public
       6              :  * License as published by the Free Software Foundation; either
       7              :  * version 2.1 of the License, or (at your option) any later version.
       8              :  *
       9              :  * This library is distributed in the hope that it will be useful,
      10              :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      11              :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      12              :  * Lesser General Public License for more details.
      13              :  *
      14              :  * You should have received a copy of the GNU Lesser General Public
      15              :  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
      16              :  *
      17              :  * Author: Vojtech Trefny <vtrefny@redhat.com>
      18              :  */
      19              : 
      20              : #include <blockdev/utils.h>
      21              : #include <check_deps.h>
      22              : #include <sys/types.h>
      23              : #include <sys/stat.h>
      24              : #include <fcntl.h>
      25              : #include <string.h>
      26              : #include <errno.h>
      27              : #include <sys/ioctl.h>
      28              : #include <linux/fs.h>
      29              : 
      30              : #include "udf.h"
      31              : #include "fs.h"
      32              : #include "common.h"
      33              : 
      34              : static volatile guint avail_deps = 0;
      35              : static GMutex deps_check_lock;
      36              : 
      37              : #define DEPS_MKUDFFS 0
      38              : #define DEPS_MKUDFFS_MASK (1 << DEPS_MKUDFFS)
      39              : #define DEPS_UDFLABEL 1
      40              : #define DEPS_UDFLABEL_MASK (1 <<  DEPS_UDFLABEL)
      41              : #define DEPS_UDFINFO 2
      42              : #define DEPS_UDFINFO_MASK (1 <<  DEPS_UDFINFO)
      43              : 
      44              : #define DEPS_LAST 3
      45              : 
      46              : static const UtilDep deps[DEPS_LAST] = {
      47              :     {"mkudffs", NULL, NULL, NULL},
      48              :     {"udflabel", NULL, NULL, NULL},
      49              :     {"udfinfo", NULL, NULL, NULL},
      50              : };
      51              : 
      52              : static guint32 fs_mode_util[BD_FS_MODE_LAST+1] = {
      53              :     DEPS_MKUDFFS_MASK,      /* mkfs */
      54              :     0,                      /* wipe */
      55              :     0,                      /* check */
      56              :     0,                      /* repair */
      57              :     DEPS_UDFLABEL_MASK,     /* set-label */
      58              :     DEPS_UDFINFO_MASK,      /* query */
      59              :     0,                      /* resize */
      60              :     DEPS_UDFLABEL_MASK,     /* set-uuid */
      61              : };
      62              : 
      63              : 
      64              : /**
      65              :  * bd_fs_udf_is_tech_avail:
      66              :  * @tech: the queried tech
      67              :  * @mode: a bit mask of queried modes of operation (#BDFSTechMode) for @tech
      68              :  * @error: (out) (optional): place to store error (details about why the @tech-@mode combination is not available)
      69              :  *
      70              :  * Returns: whether the @tech-@mode combination is available -- supported by the
      71              :  *          plugin implementation and having all the runtime dependencies available
      72              :  */
      73              : G_GNUC_INTERNAL gboolean
      74           92 : bd_fs_udf_is_tech_avail (BDFSTech tech G_GNUC_UNUSED, guint64 mode, GError **error) {
      75           92 :     guint32 required = 0;
      76           92 :     guint i = 0;
      77              : 
      78           92 :     if (mode & BD_FS_TECH_MODE_CHECK || mode & BD_FS_TECH_MODE_REPAIR) {
      79            0 :         g_set_error (error, BD_FS_ERROR, BD_FS_ERROR_TECH_UNAVAIL,
      80              :                      "UDF doesn't support checking and reparing.");
      81            0 :         return FALSE;
      82           92 :     } else if (mode & BD_FS_TECH_MODE_RESIZE) {
      83            0 :         g_set_error (error, BD_FS_ERROR, BD_FS_ERROR_TECH_UNAVAIL,
      84              :                      "UDF currently doesn't support resizing.");
      85            0 :         return FALSE;
      86              :     }
      87              : 
      88          828 :     for (i = 0; i <= BD_FS_MODE_LAST; i++)
      89          736 :         if (mode & (1 << i))
      90          184 :             required |= fs_mode_util[i];
      91              : 
      92           92 :     return check_deps (&avail_deps, required, deps, DEPS_LAST, &deps_check_lock, error);
      93              : }
      94              : 
      95              : /**
      96              :  * bd_fs_udf_info_copy: (skip)
      97              :  *
      98              :  * Creates a new copy of @data.
      99              :  */
     100            0 : BDFSUdfInfo* bd_fs_udf_info_copy (BDFSUdfInfo *data) {
     101            0 :     if (data == NULL)
     102            0 :         return NULL;
     103              : 
     104            0 :     BDFSUdfInfo *ret = g_new0 (BDFSUdfInfo, 1);
     105              : 
     106            0 :     ret->label = g_strdup (data->label);
     107            0 :     ret->uuid = g_strdup (data->uuid);
     108            0 :     ret->revision = g_strdup (data->revision);
     109            0 :     ret->lvid = g_strdup (data->lvid);
     110            0 :     ret->vid = g_strdup (data->vid);
     111            0 :     ret->block_size = data->block_size;
     112            0 :     ret->block_count = data->block_count;
     113            0 :     ret->free_blocks = data->free_blocks;
     114              : 
     115            0 :     return ret;
     116              : }
     117              : 
     118              : /**
     119              :  * bd_fs_udf_info_free: (skip)
     120              :  *
     121              :  * Frees @data.
     122              :  */
     123            0 : void bd_fs_udf_info_free (BDFSUdfInfo *data) {
     124            0 :     if (data == NULL)
     125            0 :         return;
     126              : 
     127            0 :     g_free (data->label);
     128            0 :     g_free (data->uuid);
     129            0 :     g_free (data->revision);
     130            0 :     g_free (data->lvid);
     131            0 :     g_free (data->vid);
     132            0 :     g_free (data);
     133              : }
     134              : 
     135              : /* get a valid UDF Volume Identifier from label */
     136            9 : static gchar* get_vid (const gchar *label) {
     137            9 :     gchar *vid = NULL;
     138            9 :     const gchar *next_p = NULL;
     139              :     gunichar unichar;
     140            9 :     guint pos = 0;
     141              : 
     142            9 :     if (!g_utf8_validate (label, -1, NULL))
     143            0 :         return NULL;
     144              : 
     145            9 :     if (g_utf8_strlen (label, -1) <= 15)
     146            4 :         vid = g_strdup (label);
     147              :     else {
     148              :         /* vid can be at most 30 characters (or 15 > 0xFF) so we'll truncate the label if needed */
     149            5 :         next_p = label;
     150          320 :         while (next_p && *next_p) {
     151          317 :             unichar = g_utf8_get_char (next_p);
     152          317 :             if (unichar > 0xFF) {
     153            3 :                 if (pos < 15) {
     154              :                     /* vid can have at most 15 characters > 0xFF */
     155            2 :                     vid = g_utf8_substring (label, 0, 15);
     156            2 :                     break;
     157            1 :                 } else if (pos < 30) {
     158              :                     /* cut before the "problematic" character */
     159            0 :                     vid = g_utf8_substring (label, 0, pos);
     160            0 :                     break;
     161              :                 }
     162              :             }
     163              : 
     164          315 :             next_p = g_utf8_next_char (next_p);
     165          315 :             pos++;
     166              :         }
     167              : 
     168            5 :         if (!vid) {
     169              :             /* we can't have more that 30 characters in vid so cut at 30 */
     170            3 :             vid = g_utf8_substring (label, 0, 30);
     171              :         }
     172              :     }
     173              : 
     174            9 :     return vid;
     175              : }
     176              : 
     177              : G_GNUC_INTERNAL BDExtraArg **
     178            2 : bd_fs_udf_mkfs_options (BDFSMkfsOptions *options, const BDExtraArg **extra) {
     179            2 :     GPtrArray *options_array = g_ptr_array_new ();
     180            2 :     const BDExtraArg **extra_p = NULL;
     181            2 :     g_autofree gchar *vid = NULL;
     182              : 
     183            2 :     if (options->label && g_strcmp0 (options->label, "") != 0) {
     184            1 :         vid = get_vid (options->label);
     185              : 
     186            1 :         g_ptr_array_add (options_array, bd_extra_arg_new ("--lvid", options->label));
     187            1 :         g_ptr_array_add (options_array, bd_extra_arg_new ("--vid", vid));
     188              :     }
     189              : 
     190            2 :     if (options->uuid && g_strcmp0 (options->uuid, "") != 0)
     191            0 :         g_ptr_array_add (options_array, bd_extra_arg_new ("-u", options->uuid));
     192              : 
     193            2 :     if (extra) {
     194            0 :         for (extra_p = extra; *extra_p; extra_p++)
     195            0 :             g_ptr_array_add (options_array, bd_extra_arg_copy ((BDExtraArg *) *extra_p));
     196              :     }
     197              : 
     198            2 :     g_ptr_array_add (options_array, NULL);
     199              : 
     200            2 :     return (BDExtraArg **) g_ptr_array_free (options_array, FALSE);
     201              : }
     202              : 
     203           11 : static gint get_blocksize (const gchar *device, GError **error) {
     204           11 :     gint fd = -1;
     205           11 :     gint blksize = 0;
     206              : 
     207           11 :     fd = open (device, O_RDONLY);
     208           11 :     if (fd < 0) {
     209            1 :         g_set_error (error, BD_FS_ERROR, BD_FS_ERROR_FAIL,
     210              :                     "Failed to open the device '%s' to get its block size: %s",
     211            1 :                     device, strerror_l (errno, _C_LOCALE));
     212            1 :         return -1;
     213              :     }
     214              : 
     215           10 :     if (ioctl (fd, BLKSSZGET, &blksize) < 0) {
     216            0 :         g_set_error (error, BD_FS_ERROR, BD_FS_ERROR_FAIL,
     217              :                      "Failed to get block size of the device '%s': %s",
     218            0 :                      device, strerror_l (errno, _C_LOCALE));
     219            0 :         close (fd);
     220            0 :         return -1;
     221              :     }
     222              : 
     223           10 :     close (fd);
     224              : 
     225           10 :     return blksize;
     226              : }
     227              : 
     228              : /**
     229              :  * bd_fs_udf_mkfs:
     230              :  * @device: the device to create a new UDF fs on
     231              :  * @media_type: (nullable): specify the media type or %NULL for default ('hd')
     232              :  * @revision: (nullable): UDF revision to use or %NULL for default ('2.01')
     233              :  * @block_size: block size in bytes or 0 for auto detection (device logical block size)
     234              :  * @extra: (nullable) (array zero-terminated=1): extra options for the creation (right now
     235              :  *                                                 passed to the 'mkudffs' utility)
     236              :  * @error: (out) (optional): place to store error (if any)
     237              :  *
     238              :  * Returns: whether a new UDF fs was successfully created on @device or not
     239              :  *
     240              :  * Tech category: %BD_FS_TECH_UDF-%BD_FS_TECH_MODE_MKFS
     241              :  */
     242           12 : gboolean bd_fs_udf_mkfs (const gchar *device, const gchar *media_type, gchar *revision, guint64 block_size, const BDExtraArg **extra, GError **error) {
     243           12 :     const gchar *args[7] = {"mkudffs", "--utf8", NULL, NULL, NULL, device, NULL};
     244           12 :     gint detected_bs = -1;
     245           12 :     gboolean ret = FALSE;
     246              : 
     247           12 :     if (!check_deps (&avail_deps, DEPS_MKUDFFS_MASK, deps, DEPS_LAST, &deps_check_lock, error))
     248            0 :         return FALSE;
     249              : 
     250           12 :     if (block_size != 0)
     251            1 :         args[2] = g_strdup_printf ("--blocksize=%"G_GUINT64_FORMAT"", block_size);
     252              :     else {
     253           11 :         detected_bs = get_blocksize (device, error);
     254           11 :         if (detected_bs < 0)
     255            1 :             return FALSE;
     256              : 
     257           10 :         args[2] = g_strdup_printf ("--blocksize=%d", detected_bs);
     258              :     }
     259              : 
     260           11 :     if (media_type)
     261            1 :         args[3] = g_strdup_printf ("--media-type=%s", media_type);
     262              :     else
     263           10 :         args[3] = g_strdup ("--media-type=hd");
     264              : 
     265           11 :     if (revision)
     266            1 :         args[4] = g_strdup_printf ("--udfrev=%s", revision);
     267              :     else
     268           10 :         args[4] = g_strdup ("--udfrev=0x201");
     269              : 
     270           11 :     ret = bd_utils_exec_and_report_error (args, extra, error);
     271              : 
     272           11 :     g_free ((gchar *) args[2]);
     273           11 :     g_free ((gchar *) args[3]);
     274           11 :     g_free ((gchar *) args[4]);
     275              : 
     276           11 :     return ret;
     277              : }
     278              : 
     279              : /**
     280              :  * bd_fs_udf_set_label:
     281              :  * @device: the device containing the file system to set label for
     282              :  * @label: label to set
     283              :  * @error: (out) (optional): place to store error (if any)
     284              :  *
     285              :  * Note: This sets both Volume Identifier and Logical Volume Identifier. Volume Identifier
     286              :  *       is truncated to 30 or 15 characters to accommodate to the different length limits
     287              :  *       of these labels.
     288              :  *
     289              :  * Returns: whether the label of UDF file system on the @device was
     290              :  *          successfully set or not
     291              :  *
     292              :  * Tech category: %BD_FS_TECH_UDF-%BD_FS_TECH_MODE_SET_LABEL
     293              :  */
     294            8 : gboolean bd_fs_udf_set_label (const gchar *device, const gchar *label, GError **error) {
     295            8 :     const gchar *args[6] = {"udflabel", "--utf8", NULL, NULL, device, NULL};
     296            8 :     g_autofree gchar *vid = NULL;
     297            8 :     gboolean ret = FALSE;
     298              : 
     299            8 :     if (!check_deps (&avail_deps, DEPS_UDFLABEL_MASK, deps, DEPS_LAST, &deps_check_lock, error))
     300            0 :         return FALSE;
     301              : 
     302            8 :     if (!bd_fs_udf_check_label (label, error))
     303            0 :         return FALSE;
     304              : 
     305            8 :     vid = get_vid (label);
     306              : 
     307            8 :     args[2] = g_strdup_printf ("--lvid=%s", label);
     308            8 :     args[3] = g_strdup_printf ("--vid=%s", vid);
     309              : 
     310            8 :     ret = bd_utils_exec_and_report_error (args, NULL, error);
     311              : 
     312            8 :     g_free ((gchar *) args[2]);
     313            8 :     g_free ((gchar *) args[3]);
     314              : 
     315            8 :     return ret;
     316              : }
     317              : 
     318              : /**
     319              :  * bd_fs_udf_check_label:
     320              :  * @label: label to check
     321              :  * @error: (out) (optional): place to store error
     322              :  *
     323              :  * Note: This checks only whether @label adheres the length limits for Logical Volume Identifier,
     324              :  *       not the stricter limits for Volume Identifier.
     325              :  *
     326              :  * Returns: whether @label is a valid label for the UDF file system or not
     327              :  *          (reason is provided in @error)
     328              :  *
     329              :  * Tech category: always available
     330              :  */
     331           15 : gboolean bd_fs_udf_check_label (const gchar *label, GError **error) {
     332           15 :     const gchar *next_p = NULL;
     333              :     gunichar unichar;
     334           15 :     gint len = 0;
     335              : 
     336           15 :     if (g_str_is_ascii (label)) {
     337            8 :         if (strlen (label) > 126) {
     338            2 :             g_set_error (error, BD_FS_ERROR, BD_FS_ERROR_LABEL_INVALID,
     339              :                          "Label for UDF filesystem can be at most 126 characters long.");
     340            2 :             return FALSE;
     341              :         }
     342              : 
     343            6 :         return TRUE;
     344              :     }
     345              : 
     346            7 :     if (g_utf8_validate (label, -1, NULL)) {
     347            7 :         len = g_utf8_strlen (label, -1);
     348            7 :         if (len <= 63)
     349              :             /* utf-8 and <= 63 will be always valid */
     350            4 :             return TRUE;
     351              : 
     352            3 :         if (len > 126) {
     353            0 :             g_set_error (error, BD_FS_ERROR, BD_FS_ERROR_LABEL_INVALID,
     354              :                          "Label for UDF filesystem can be at most 126 characters long.");
     355            0 :             return FALSE;
     356              :         }
     357              : 
     358            3 :         next_p = label;
     359          255 :         while (next_p && *next_p) {
     360          253 :             unichar = g_utf8_get_char (next_p);
     361          253 :             if (unichar > 0xFF) {
     362            1 :                 g_set_error (error, BD_FS_ERROR, BD_FS_ERROR_LABEL_INVALID,
     363              :                              "Label for UDF filesystem containing unicode characters above U+FF can "\
     364              :                              "be at most 63 characters long.");
     365            1 :                 return FALSE;
     366              :             }
     367              : 
     368          252 :             next_p = g_utf8_next_char (next_p);
     369              :         }
     370              :     } else {
     371            0 :         g_set_error (error, BD_FS_ERROR, BD_FS_ERROR_LABEL_INVALID,
     372              :                      "Label for UDF filesystem must be a valid UTF-8 string.");
     373            0 :         return FALSE;
     374              :     }
     375              : 
     376            2 :     return TRUE;
     377              : }
     378              : 
     379              : /**
     380              :  * bd_fs_udf_set_uuid:
     381              :  * @device: the device containing the file system to set the UUID (serial number) for
     382              :  * @uuid: (nullable): UUID to set or %NULL to generate a new one
     383              :  * @error: (out) (optional): place to store error (if any)
     384              :  *
     385              :  * Returns: whether the UUID of the UDF file system on the @device was
     386              :  *          successfully set or not
     387              :  *
     388              :  * Tech category: %BD_FS_TECH_UDF-%BD_FS_TECH_MODE_SET_UUID
     389              :  */
     390            4 : gboolean bd_fs_udf_set_uuid (const gchar *device, const gchar *uuid, GError **error) {
     391            4 :     gboolean ret = FALSE;
     392            4 :     const gchar *args[4] = {"udflabel", NULL, device, NULL};
     393              : 
     394            4 :     if (!check_deps (&avail_deps, DEPS_UDFLABEL_MASK, deps, DEPS_LAST, &deps_check_lock, error))
     395            0 :         return FALSE;
     396              : 
     397            4 :     if (!uuid)
     398            2 :         args[1] = g_strdup ("--uuid=random");
     399              :     else
     400            2 :         args[1] = g_strdup_printf ("--uuid=%s", uuid);
     401              : 
     402            4 :     ret = bd_utils_exec_and_report_error (args, NULL, error);
     403              : 
     404            4 :     g_free ((gchar *) args[1]);
     405            4 :     return ret;
     406              : }
     407              : 
     408              : /**
     409              :  * bd_fs_udf_check_uuid:
     410              :  * @uuid: UUID to check
     411              :  * @error: (out) (optional): place to store error
     412              :  *
     413              :  * Returns: whether @uuid is a valid UUID for the UDF file system or not
     414              :  *          (reason is provided in @error)
     415              :  *
     416              :  * Tech category: always available
     417              :  */
     418            5 : gboolean bd_fs_udf_check_uuid (const gchar *uuid, GError **error) {
     419            5 :     size_t len = 0;
     420              : 
     421            5 :     len = strlen (uuid);
     422            5 :     if (len != 16) {
     423            1 :         g_set_error (error, BD_FS_ERROR, BD_FS_ERROR_UUID_INVALID,
     424              :                      "UUID for UDF filesystem must be 16 characters long.");
     425            1 :         return FALSE;
     426              :     }
     427              : 
     428           37 :     for (size_t i = 0; i < len; i++) {
     429           35 :         if (!g_ascii_isxdigit (uuid[i]) || (!g_ascii_isdigit (uuid[i]) && !g_ascii_islower (uuid[i]))) {
     430            2 :             g_set_error (error, BD_FS_ERROR, BD_FS_ERROR_UUID_INVALID,
     431              :                          "UUID for UDF filesystem must be a lowercase hexadecimal number.");
     432            2 :             return FALSE;
     433              :         }
     434              :     }
     435              : 
     436            2 :     return TRUE;
     437              : }
     438              : 
     439              : /**
     440              :  * parse_udf_vars:
     441              :  * @str: string to parse
     442              :  * @num_items: (out): number of parsed items
     443              :  *
     444              :  * Returns: (transfer full): a GHashTable containing key-value items parsed from the @string
     445              :  */
     446           14 : static GHashTable* parse_udf_vars (const gchar *str, guint *num_items) {
     447           14 :     GHashTable *table = NULL;
     448           14 :     gchar **items = NULL;
     449           14 :     gchar **item_p = NULL;
     450           14 :     gchar **key_val = NULL;
     451              : 
     452           14 :     table = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
     453           14 :     *num_items = 0;
     454              : 
     455           14 :     items = g_strsplit (str, "\n", 0);
     456          529 :     for (item_p=items; *item_p; item_p++) {
     457          515 :         if (g_str_has_prefix (*item_p, "start="))
     458          123 :             continue;
     459          392 :         key_val = g_strsplit (*item_p, "=", 2);
     460          392 :         if (g_strv_length (key_val) == 2) {
     461              :             /* we only want to process valid lines (with the '=' character) */
     462          378 :             g_hash_table_insert (table, key_val[0], key_val[1]);
     463          378 :             g_free (key_val);
     464          378 :             (*num_items)++;
     465              :         } else
     466              :             /* invalid line, just free key_val */
     467           14 :             g_strfreev (key_val);
     468              :     }
     469              : 
     470           14 :     g_strfreev (items);
     471           14 :     return table;
     472              : }
     473              : 
     474           14 : static BDFSUdfInfo* get_udf_data_from_table (GHashTable *table) {
     475           14 :     BDFSUdfInfo *data = g_new0 (BDFSUdfInfo, 1);
     476           14 :     gchar *value = NULL;
     477              : 
     478           14 :     data->revision = g_strdup ((gchar*) g_hash_table_lookup (table, "udfrev"));
     479           14 :     data->vid = g_strdup ((gchar*) g_hash_table_lookup (table, "vid"));
     480           14 :     data->lvid = g_strdup ((gchar*) g_hash_table_lookup (table, "lvid"));
     481              : 
     482           14 :     value = (gchar*) g_hash_table_lookup (table, "blocksize");
     483           14 :     if (value)
     484           14 :         data->block_size = g_ascii_strtoull (value, NULL, 0);
     485              :     else
     486            0 :         data->block_size = 0;
     487              : 
     488           14 :     value = (gchar*) g_hash_table_lookup (table, "blocks");
     489           14 :     if (value)
     490           14 :         data->block_count = g_ascii_strtoull (value, NULL, 0);
     491              :     else
     492            0 :         data->block_count = 0;
     493              : 
     494           14 :     value = (gchar*) g_hash_table_lookup (table, "freeblocks");
     495           14 :     if (value)
     496           14 :         data->free_blocks = g_ascii_strtoull (value, NULL, 0);
     497              :     else
     498            0 :         data->free_blocks = 0;
     499              : 
     500           14 :     g_hash_table_destroy (table);
     501              : 
     502           14 :     return data;
     503              : }
     504              : 
     505              : /**
     506              :  * bd_fs_udf_get_info:
     507              :  * @device: the device containing the file system to get info for
     508              :  * @error: (out) (optional): place to store error (if any)
     509              :  *
     510              :  * Returns: (transfer full): information about the file system on @device or
     511              :  *                           %NULL in case of error
     512              :  *
     513              :  * Tech category: %BD_FS_TECH_UDF-%BD_FS_TECH_MODE_QUERY
     514              :  */
     515           14 : BDFSUdfInfo* bd_fs_udf_get_info (const gchar *device, GError **error) {
     516           14 :     const gchar *args[4] = {"udfinfo", "--utf8", device, NULL};
     517           14 :     gboolean success = FALSE;
     518           14 :     gchar *output = NULL;
     519           14 :     BDFSUdfInfo *ret = NULL;
     520           14 :     GHashTable *table = NULL;
     521           14 :     guint num_items = 0;
     522              : 
     523           14 :     if (!check_deps (&avail_deps, DEPS_UDFINFO_MASK, deps, DEPS_LAST, &deps_check_lock, error))
     524            0 :         return NULL;
     525              : 
     526           14 :     success = bd_utils_exec_and_capture_output (args, NULL, &output, error);
     527           14 :     if (!success) {
     528              :         /* error is already populated */
     529            0 :         return NULL;
     530              :     }
     531              : 
     532           14 :     table = parse_udf_vars (output, &num_items);
     533           14 :     g_free (output);
     534           14 :     if (!table || (num_items == 0)) {
     535              :         /* something bad happened or some expected items were missing  */
     536            0 :         g_set_error (error, BD_FS_ERROR, BD_FS_ERROR_PARSE, "Failed to parse UDF file system information");
     537            0 :         if (table)
     538            0 :             g_hash_table_destroy (table);
     539            0 :         return NULL;
     540              :     }
     541              : 
     542           14 :     ret = get_udf_data_from_table (table);
     543           14 :     if (!ret) {
     544            0 :         g_set_error (error, BD_FS_ERROR, BD_FS_ERROR_PARSE, "Failed to parse UDF file system information");
     545            0 :         return NULL;
     546              :     }
     547              : 
     548           14 :     success = get_uuid_label (device, &(ret->uuid), &(ret->label), error);
     549           14 :     if (!success) {
     550              :         /* error is already populated */
     551            0 :         bd_fs_udf_info_free (ret);
     552            0 :         return NULL;
     553              :     }
     554              : 
     555           14 :     return ret;
     556              : }
        

Generated by: LCOV version 2.0-1