struct mp_archive *mp_archive_new(struct mp_log *log, struct stream *src, int flags) { struct mp_archive *mpa = talloc_zero(NULL, struct mp_archive); mpa->log = log; mpa->locale = newlocale(LC_ALL_MASK, "C.UTF-8", (locale_t)0); if (!mpa->locale) { mpa->locale = newlocale(LC_CTYPE_MASK, "", (locale_t)0); if (!mpa->locale) goto err; } mpa->arch = archive_read_new(); mpa->primary_src = src; if (!mpa->arch) goto err; // first volume is the primary streame if (!add_volume(log ,mpa, src, src->url)) goto err; // try to open other volumes char** volumes = find_volumes(src); for (int i = 0; volumes[i]; i++) { if (!add_volume(log, mpa, NULL, volumes[i])) { talloc_free(volumes); goto err; } } talloc_free(volumes); locale_t oldlocale = uselocale(mpa->locale); archive_read_support_format_7zip(mpa->arch); archive_read_support_format_iso9660(mpa->arch); archive_read_support_format_rar(mpa->arch); archive_read_support_format_zip(mpa->arch); archive_read_support_filter_bzip2(mpa->arch); archive_read_support_filter_gzip(mpa->arch); archive_read_support_filter_xz(mpa->arch); if (flags & MP_ARCHIVE_FLAG_UNSAFE) { archive_read_support_format_gnutar(mpa->arch); archive_read_support_format_tar(mpa->arch); } archive_read_set_read_callback(mpa->arch, read_cb); archive_read_set_skip_callback(mpa->arch, skip_cb); archive_read_set_switch_callback(mpa->arch, switch_cb); archive_read_set_open_callback(mpa->arch, open_cb); archive_read_set_close_callback(mpa->arch, close_cb); if (mpa->primary_src->seekable) archive_read_set_seek_callback(mpa->arch, seek_cb); bool fail = archive_read_open1(mpa->arch) < ARCHIVE_OK; uselocale(oldlocale); if (fail) goto err; return mpa; err: mp_archive_free(mpa); return NULL; }
/** * ubi_scan_add_used - add physical eraseblock to the scanning information. * @ubi: UBI device description object * @si: scanning information * @pnum: the physical eraseblock number * @ec: erase counter * @vid_hdr: the volume identifier header * @bitflips: if bit-flips were detected when this physical eraseblock was read * * This function adds information about a used physical eraseblock to the * 'used' tree of the corresponding volume. The function is rather complex * because it has to handle cases when this is not the first physical * eraseblock belonging to the same logical eraseblock, and the newer one has * to be picked, while the older one has to be dropped. This function returns * zero in case of success and a negative error code in case of failure. */ int ubi_scan_add_used(struct ubi_device *ubi, struct ubi_scan_info *si, int pnum, int ec, const struct ubi_vid_hdr *vid_hdr, int bitflips) { int err, vol_id, lnum; unsigned long long sqnum; struct ubi_scan_volume *sv; struct ubi_scan_leb *seb; struct rb_node **p, *parent = NULL; vol_id = be32_to_cpu(vid_hdr->vol_id); lnum = be32_to_cpu(vid_hdr->lnum); sqnum = be64_to_cpu(vid_hdr->sqnum); dbg_bld("PEB %d, LEB %d:%d, EC %d, sqnum %llu, bitflips %d", pnum, vol_id, lnum, ec, sqnum, bitflips); sv = add_volume(si, vol_id, pnum, vid_hdr); if (IS_ERR(sv)) return PTR_ERR(sv); if (si->max_sqnum < sqnum) si->max_sqnum = sqnum; /* * Walk the RB-tree of logical eraseblocks of volume @vol_id to look * if this is the first instance of this logical eraseblock or not. */ p = &sv->root.rb_node; while (*p) { int cmp_res; parent = *p; seb = rb_entry(parent, struct ubi_scan_leb, u.rb); if (lnum != seb->lnum) { if (lnum < seb->lnum) p = &(*p)->rb_left; else p = &(*p)->rb_right; continue; } /* * There is already a physical eraseblock describing the same * logical eraseblock present. */ dbg_bld("this LEB already exists: PEB %d, sqnum %llu, " "EC %d", seb->pnum, seb->sqnum, seb->ec); /* * Make sure that the logical eraseblocks have different * sequence numbers. Otherwise the image is bad. * * However, if the sequence number is zero, we assume it must * be an ancient UBI image from the era when UBI did not have * sequence numbers. We still can attach these images, unless * there is a need to distinguish between old and new * eraseblocks, in which case we'll refuse the image in * 'compare_lebs()'. In other words, we attach old clean * images, but refuse attaching old images with duplicated * logical eraseblocks because there was an unclean reboot. */ if (seb->sqnum == sqnum && sqnum != 0) { ubi_err("two LEBs with same sequence number %llu", sqnum); ubi_dbg_dump_seb(seb, 0); ubi_dbg_dump_vid_hdr(vid_hdr); return -EINVAL; } /* * Now we have to drop the older one and preserve the newer * one. */ cmp_res = compare_lebs(ubi, seb, pnum, vid_hdr); if (cmp_res < 0) return cmp_res; if (cmp_res & 1) { /* * This logical eraseblock is newer then the one * found earlier. */ err = validate_vid_hdr(vid_hdr, sv, pnum); if (err) return err; if (cmp_res & 4) err = add_to_list(si, seb->pnum, seb->ec, &si->corr); else err = add_to_list(si, seb->pnum, seb->ec, &si->erase); if (err) return err; seb->ec = ec; seb->pnum = pnum; seb->scrub = ((cmp_res & 2) || bitflips); seb->sqnum = sqnum; if (sv->highest_lnum == lnum) sv->last_data_size = be32_to_cpu(vid_hdr->data_size); return 0; } else { /* * This logical eraseblock is older than the one found * previously. */ if (cmp_res & 4) return add_to_list(si, pnum, ec, &si->corr); else return add_to_list(si, pnum, ec, &si->erase); } } /* * We've met this logical eraseblock for the first time, add it to the * scanning information. */ err = validate_vid_hdr(vid_hdr, sv, pnum); if (err) return err; seb = kmalloc(sizeof(struct ubi_scan_leb), GFP_KERNEL); if (!seb) return -ENOMEM; seb->ec = ec; seb->pnum = pnum; seb->lnum = lnum; seb->sqnum = sqnum; seb->scrub = bitflips; if (sv->highest_lnum <= lnum) { sv->highest_lnum = lnum; sv->last_data_size = be32_to_cpu(vid_hdr->data_size); } sv->leb_count += 1; rb_link_node(&seb->u.rb, parent, p); rb_insert_color(&seb->u.rb, &sv->root); return 0; }
/** * ubi_scan_add_used - add information about a physical eraseblock to the * scanning information. * @ubi: UBI device description object * @si: scanning information * @pnum: the physical eraseblock number * @ec: erase counter * @vid_hdr: the volume identifier header * @bitflips: if bit-flips were detected when this physical eraseblock was read * * This function adds information about a used physical eraseblock to the * 'used' tree of the corresponding volume. The function is rather complex * because it has to handle cases when this is not the first physical * eraseblock belonging to the same logical eraseblock, and the newer one has * to be picked, while the older one has to be dropped. This function returns * zero in case of success and a negative error code in case of failure. */ int ubi_scan_add_used(struct ubi_device *ubi, struct ubi_scan_info *si, int pnum, int ec, const struct ubi_vid_hdr *vid_hdr, int bitflips) { int err, vol_id, lnum; uint32_t leb_ver; unsigned long long sqnum; struct ubi_scan_volume *sv; struct ubi_scan_leb *seb; struct rb_node **p, *parent = NULL; vol_id = be32_to_cpu(vid_hdr->vol_id); lnum = be32_to_cpu(vid_hdr->lnum); sqnum = be64_to_cpu(vid_hdr->sqnum); leb_ver = be32_to_cpu(vid_hdr->leb_ver); dbg_bld("PEB %d, LEB %d:%d, EC %d, sqnum %llu, ver %u, bitflips %d", pnum, vol_id, lnum, ec, sqnum, leb_ver, bitflips); sv = add_volume(si, vol_id, pnum, vid_hdr); if (IS_ERR(sv) < 0) return PTR_ERR(sv); if (si->max_sqnum < sqnum) si->max_sqnum = sqnum; /* * Walk the RB-tree of logical eraseblocks of volume @vol_id to look * if this is the first instance of this logical eraseblock or not. */ p = &sv->root.rb_node; while (*p) { int cmp_res; parent = *p; seb = rb_entry(parent, struct ubi_scan_leb, u.rb); if (lnum != seb->lnum) { if (lnum < seb->lnum) p = &(*p)->rb_left; else p = &(*p)->rb_right; continue; } /* * There is already a physical eraseblock describing the same * logical eraseblock present. */ dbg_bld("this LEB already exists: PEB %d, sqnum %llu, " "LEB ver %u, EC %d", seb->pnum, seb->sqnum, seb->leb_ver, seb->ec); /* * Make sure that the logical eraseblocks have different * versions. Otherwise the image is bad. */ if (seb->leb_ver == leb_ver && leb_ver != 0) { ubi_err("two LEBs with same version %u", leb_ver); ubi_dbg_dump_seb(seb, 0); ubi_dbg_dump_vid_hdr(vid_hdr); return -EINVAL; } /* * Make sure that the logical eraseblocks have different * sequence numbers. Otherwise the image is bad. * * FIXME: remove 'sqnum != 0' check when leb_ver is removed. */ if (seb->sqnum == sqnum && sqnum != 0) { ubi_err("two LEBs with same sequence number %llu", sqnum); ubi_dbg_dump_seb(seb, 0); ubi_dbg_dump_vid_hdr(vid_hdr); return -EINVAL; } /* * Now we have to drop the older one and preserve the newer * one. */ cmp_res = compare_lebs(ubi, seb, pnum, vid_hdr); if (cmp_res < 0) return cmp_res; if (cmp_res & 1) { /* * This logical eraseblock is newer then the one * found earlier. */ err = validate_vid_hdr(vid_hdr, sv, pnum); if (err) return err; if (cmp_res & 4) err = add_to_list(si, seb->pnum, seb->ec, &si->corr); else err = add_to_list(si, seb->pnum, seb->ec, &si->erase); if (err) return err; seb->ec = ec; seb->pnum = pnum; seb->scrub = ((cmp_res & 2) || bitflips); seb->sqnum = sqnum; seb->leb_ver = leb_ver; if (sv->highest_lnum == lnum) sv->last_data_size = be32_to_cpu(vid_hdr->data_size); return 0; } else { /* * This logical eraseblock is older then the one found * previously. */ if (cmp_res & 4) return add_to_list(si, pnum, ec, &si->corr); else return add_to_list(si, pnum, ec, &si->erase); } } /* * We've met this logical eraseblock for the first time, add it to the * scanning information. */ err = validate_vid_hdr(vid_hdr, sv, pnum); if (err) return err; seb = kmalloc(sizeof(struct ubi_scan_leb), GFP_KERNEL); if (!seb) return -ENOMEM; seb->ec = ec; seb->pnum = pnum; seb->lnum = lnum; seb->sqnum = sqnum; seb->scrub = bitflips; seb->leb_ver = leb_ver; if (sv->highest_lnum <= lnum) { sv->highest_lnum = lnum; sv->last_data_size = be32_to_cpu(vid_hdr->data_size); } sv->leb_count += 1; rb_link_node(&seb->u.rb, parent, p); rb_insert_color(&seb->u.rb, &sv->root); return 0; }
/* HAL callback for new device */ static void hal_new_device( LibHalContext *ctx, const char *udi ) { DBusError error; #ifndef HAVE_LIBUDEV char *subsys = NULL; #endif char *parent = NULL; char *mount_point = NULL; char *device = NULL; char *type = NULL; char *uuid_str = NULL; GUID guid, *guid_ptr = NULL; enum device_type drive_type; p_dbus_error_init( &error ); #ifndef HAVE_LIBUDEV if ((subsys = p_libhal_device_get_property_string( ctx, udi, "info.subsystem", NULL )) && !strcmp( subsys, "usb_device" )) add_usb_devices(); #endif if (!(device = p_libhal_device_get_property_string( ctx, udi, "block.device", &error ))) goto done; if (!(mount_point = p_libhal_device_get_property_string( ctx, udi, "volume.mount_point", &error ))) goto done; if (!(parent = p_libhal_device_get_property_string( ctx, udi, "info.parent", &error ))) goto done; if (!(uuid_str = p_libhal_device_get_property_string( ctx, udi, "volume.uuid", &error ))) p_dbus_error_free( &error ); /* ignore error */ else guid_ptr = parse_uuid( &guid, uuid_str ); if (!(type = p_libhal_device_get_property_string( ctx, parent, "storage.drive_type", &error ))) p_dbus_error_free( &error ); /* ignore error */ if (type && !strcmp( type, "cdrom" )) drive_type = DEVICE_CDROM; else if (type && !strcmp( type, "floppy" )) drive_type = DEVICE_FLOPPY; else drive_type = DEVICE_UNKNOWN; if (p_libhal_device_get_property_bool( ctx, parent, "storage.removable", &error )) { add_dos_device( -1, udi, device, mount_point, drive_type, guid_ptr ); /* add property watch for mount point */ p_libhal_device_add_property_watch( ctx, udi, &error ); } else if (guid_ptr) add_volume( udi, device, mount_point, DEVICE_HARDDISK_VOL, guid_ptr ); done: #ifndef HAVE_LIBUDEV if (subsys) p_libhal_free_string( subsys ); #endif if (type) p_libhal_free_string( type ); if (parent) p_libhal_free_string( parent ); if (device) p_libhal_free_string( device ); if (uuid_str) p_libhal_free_string( uuid_str ); if (mount_point) p_libhal_free_string( mount_point ); p_dbus_error_free( &error ); }
static void udisks2_add_device( const char *udi, DBusMessageIter *dict, DBusMessageIter *block ) { DBusMessageIter iter, variant, paths, string; const char *device = NULL; const char *mount_point = NULL; const char *type = NULL; const char *drive = NULL; GUID guid, *guid_ptr = NULL; const char *iface, *name; int removable = FALSE; enum device_type drive_type = DEVICE_UNKNOWN; while ((iface = udisks_next_dict_entry( block, &iter ))) { if (!strcmp( iface, "org.freedesktop.UDisks2.Filesystem" )) { while ((name = udisks_next_dict_entry( &iter, &variant ))) { if (!strcmp( name, "MountPoints" )) { p_dbus_message_iter_recurse( &variant, &paths ); if (p_dbus_message_iter_get_arg_type( &paths ) == DBUS_TYPE_ARRAY) { p_dbus_message_iter_recurse( &variant, &string ); mount_point = udisks2_string_from_array( &string ); } } } } if (!strcmp( iface, "org.freedesktop.UDisks2.Block" )) { while ((name = udisks_next_dict_entry( &iter, &variant ))) { if (!strcmp( name, "Device" )) device = udisks2_string_from_array( &variant ); else if (!strcmp( name, "IdType" )) p_dbus_message_iter_get_basic( &variant, &type ); else if (!strcmp( name, "Drive" )) { p_dbus_message_iter_get_basic( &variant, &drive ); udisks2_get_drive_info( drive, dict, &drive_type, &removable ); } else if (!strcmp( name, "IdUUID" )) { const char *uuid_str; if (p_dbus_message_iter_get_arg_type( &variant ) == DBUS_TYPE_ARRAY) uuid_str = udisks2_string_from_array( &variant ); else p_dbus_message_iter_get_basic( &variant, &uuid_str ); guid_ptr = parse_uuid( &guid, uuid_str ); } } } } TRACE( "udi %s device %s mount point %s uuid %s type %s removable %u\n", debugstr_a(udi), debugstr_a(device), debugstr_a(mount_point), debugstr_guid(guid_ptr), debugstr_a(type), removable ); if (type) { if (!strcmp( type, "iso9660" )) { removable = TRUE; drive_type = DEVICE_CDROM; } else if (!strcmp( type, "udf" )) { removable = TRUE; drive_type = DEVICE_DVD; } } if (device) { if (removable) add_dos_device( -1, udi, device, mount_point, drive_type, guid_ptr ); else if (guid_ptr) add_volume( udi, device, mount_point, DEVICE_HARDDISK_VOL, guid_ptr ); } }
/* UDisks callback for new device */ static void udisks_new_device( const char *udi ) { static const char *dev_name = "org.freedesktop.UDisks.Device"; DBusMessage *request, *reply; DBusMessageIter iter, variant; DBusError error; const char *device = NULL; const char *mount_point = NULL; const char *type = NULL; GUID guid, *guid_ptr = NULL; int removable = FALSE; enum device_type drive_type = DEVICE_UNKNOWN; request = p_dbus_message_new_method_call( "org.freedesktop.UDisks", udi, "org.freedesktop.DBus.Properties", "GetAll" ); if (!request) return; p_dbus_message_iter_init_append( request, &iter ); p_dbus_message_iter_append_basic( &iter, DBUS_TYPE_STRING, &dev_name ); p_dbus_error_init( &error ); reply = p_dbus_connection_send_with_reply_and_block( connection, request, -1, &error ); p_dbus_message_unref( request ); if (!reply) { WARN( "failed: %s\n", error.message ); p_dbus_error_free( &error ); return; } p_dbus_error_free( &error ); p_dbus_message_iter_init( reply, &iter ); if (p_dbus_message_iter_get_arg_type( &iter ) == DBUS_TYPE_ARRAY) { const char *name; p_dbus_message_iter_recurse( &iter, &iter ); while ((name = udisks_next_dict_entry( &iter, &variant ))) { if (!strcmp( name, "DeviceFile" )) p_dbus_message_iter_get_basic( &variant, &device ); else if (!strcmp( name, "DeviceIsRemovable" )) p_dbus_message_iter_get_basic( &variant, &removable ); else if (!strcmp( name, "IdType" )) p_dbus_message_iter_get_basic( &variant, &type ); else if (!strcmp( name, "DriveMediaCompatibility" )) drive_type = udisks_parse_media_compatibility( &variant ); else if (!strcmp( name, "DeviceMountPaths" )) { DBusMessageIter paths; p_dbus_message_iter_recurse( &variant, &paths ); if (p_dbus_message_iter_get_arg_type( &paths ) == DBUS_TYPE_STRING) p_dbus_message_iter_get_basic( &paths, &mount_point ); } else if (!strcmp( name, "IdUuid" )) { char *uuid_str; p_dbus_message_iter_get_basic( &variant, &uuid_str ); guid_ptr = parse_uuid( &guid, uuid_str ); } } } TRACE( "udi %s device %s mount point %s uuid %s type %s removable %u\n", debugstr_a(udi), debugstr_a(device), debugstr_a(mount_point), debugstr_guid(guid_ptr), debugstr_a(type), removable ); if (type) { if (!strcmp( type, "iso9660" )) { removable = TRUE; drive_type = DEVICE_CDROM; } else if (!strcmp( type, "udf" )) { removable = TRUE; drive_type = DEVICE_DVD; } } if (device) { if (removable) add_dos_device( -1, udi, device, mount_point, drive_type, guid_ptr ); else if (guid_ptr) add_volume( udi, device, mount_point, DEVICE_HARDDISK_VOL, guid_ptr ); } p_dbus_message_unref( reply ); }