Beispiel #1
0
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;
}
Beispiel #2
0
/**
 * 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;
}
Beispiel #3
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;
}
Beispiel #4
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 );
}
Beispiel #5
0
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 );
    }
}
Beispiel #6
0
/* 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 );
}