fpi-data.c 23.7 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
/*
 * Fingerprint data handling and storage
 * Copyright (C) 2007 Daniel Drake <dsd@gentoo.org>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 */

#include <config.h>
21
#include <errno.h>
22
#include <stdlib.h>
23
#include <string.h>
24 25 26
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
27 28

#include <glib.h>
29
#include <glib/gstdio.h>
30 31 32

#include "fp_internal.h"

33 34
#define DIR_PERMS 0700

35 36 37 38 39 40 41 42 43 44 45 46 47
struct fpi_print_data_fp2 {
	char prefix[3];
	uint16_t driver_id;
	uint32_t devtype;
	unsigned char data_type;
	unsigned char data[0];
} __attribute__((__packed__));

struct fpi_print_data_item_fp2 {
	uint32_t length;
	unsigned char data[0];
} __attribute__((__packed__));

48 49 50
/**
 * SECTION: print_data
 * @title: Stored prints
51
 * @short_description: Stored prints functions
52 53
 *
 * Stored prints are represented by a structure named #fp_print_data.
Daniel Drake's avatar
Daniel Drake committed
54 55 56 57 58 59 60 61 62 63 64 65 66
 * Stored prints are originally obtained from an enrollment function such as
 * fp_enroll_finger().
 *
 * This page documents the various operations you can do with a stored print.
 * Note that by default, "stored prints" are not actually stored anywhere
 * except in RAM. For the simple scenarios, libfprint provides a simple API
 * for you to save and load the stored prints referring to a single user in
 * their home directory. For more advanced users, libfprint provides APIs for
 * you to convert print data to a byte string, and to reconstruct stored prints
 * from such data at a later point. You are welcome to store these byte strings
 * in any fashion that suits you.
 */

67
/*
68 69
 * SECTION: fpi-data
 * @title: Stored prints creation
70
 * @short_description: Stored prints creation functions
71 72 73 74 75 76
 *
 * Stored print can be loaded and created by certain drivers which do their own
 * print matching in hardware. Most drivers will not be using those functions.
 * See #fp_print_data for the public API counterpart.
 */

77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93
static char *base_store = NULL;

static void storage_setup(void)
{
	const char *homedir;

	homedir = g_getenv("HOME");
	if (!homedir)
		homedir = g_get_home_dir();
	if (!homedir)
		return;

	base_store = g_build_filename(homedir, ".fprint/prints", NULL);
	g_mkdir_with_parents(base_store, DIR_PERMS);
	/* FIXME handle failure */
}

94 95 96 97 98
void fpi_data_exit(void)
{
	g_free(base_store);
}

Daniel Drake's avatar
Daniel Drake committed
99 100 101 102 103
#define FP_FINGER_IS_VALID(finger) \
	((finger) >= LEFT_THUMB && (finger) <= RIGHT_LITTLE)

/* for debug messages only */
static const char *finger_num_to_str(enum fp_finger finger)
104 105
{
	const char *names[] = {
Daniel Drake's avatar
Daniel Drake committed
106 107 108 109 110 111 112 113 114 115
		[LEFT_THUMB] = "left thumb",
		[LEFT_INDEX] = "left index",
		[LEFT_MIDDLE] = "left middle",
		[LEFT_RING] = "left ring",
		[LEFT_LITTLE] = "left little",
		[RIGHT_THUMB] = "right thumb",
		[RIGHT_INDEX] = "right index",
		[RIGHT_MIDDLE] = "right middle",
		[RIGHT_RING] = "right ring",
		[RIGHT_LITTLE] = "right little",
116
	};
Daniel Drake's avatar
Daniel Drake committed
117 118
	if (!FP_FINGER_IS_VALID(finger))
		return "UNKNOWN";
119 120 121
	return names[finger];
}

122
static struct fp_print_data *print_data_new(uint16_t driver_id,
123
	uint32_t devtype, enum fp_print_data_type type)
124
{
125 126
	struct fp_print_data *data = g_malloc0(sizeof(*data));
	fp_dbg("driver=%02x devtype=%04x", driver_id, devtype);
127 128 129
	data->driver_id = driver_id;
	data->devtype = devtype;
	data->type = type;
Daniel Drake's avatar
Daniel Drake committed
130
	return data;
131 132
}

133
static void fpi_print_data_item_free(struct fp_print_data_item *item)
134 135 136 137 138 139
{
	g_free(item);
}

struct fp_print_data_item *fpi_print_data_item_new(size_t length)
{
140
	struct fp_print_data_item *item = g_malloc0(sizeof(*item) + length);
141 142 143 144 145 146
	item->length = length;

	return item;
}

struct fp_print_data *fpi_print_data_new(struct fp_dev *dev)
147 148
{
	return print_data_new(dev->drv->id, dev->devtype,
149
		fpi_driver_get_data_type(dev->drv));
150 151
}

152 153 154 155 156 157 158 159 160 161 162 163 164
struct fp_print_data_item *
fpi_print_data_get_item(struct fp_print_data *data)
{
	return data->prints->data;
}

void
fpi_print_data_add_item(struct fp_print_data      *data,
			struct fp_print_data_item *item)
{
	data->prints = g_slist_prepend(data->prints, item);
}

165 166 167 168 169 170
/**
 * fp_print_data_get_data:
 * @data: the stored print
 * @ret: output location for the data buffer. Must be freed with free()
 * after use.

Daniel Drake's avatar
Daniel Drake committed
171 172 173
 * Convert a stored print into a unified representation inside a data buffer.
 * You can then store this data buffer in any way that suits you, and load
 * it back at some later time using fp_print_data_from_data().
174 175
 *
 * Returns: the size of the freshly allocated buffer, or 0 on error.
Daniel Drake's avatar
Daniel Drake committed
176
 */
177 178 179
API_EXPORTED size_t fp_print_data_get_data(struct fp_print_data *data,
	unsigned char **ret)
{
180 181 182 183 184 185
	struct fpi_print_data_fp2 *out_data;
	struct fpi_print_data_item_fp2 *out_item;
	struct fp_print_data_item *item;
	size_t buflen = 0;
	GSList *list_item;
	unsigned char *buf;
186

187
	G_DEBUG_HERE();
188

189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220
	list_item = data->prints;
	while (list_item) {
		item = list_item->data;
		buflen += sizeof(*out_item);
		buflen += item->length;
		list_item = g_slist_next(list_item);
	}

	buflen += sizeof(*out_data);
	out_data = g_malloc(buflen);

	*ret = (unsigned char *) out_data;
	buf = out_data->data;
	out_data->prefix[0] = 'F';
	out_data->prefix[1] = 'P';
	out_data->prefix[2] = '2';
	out_data->driver_id = GUINT16_TO_LE(data->driver_id);
	out_data->devtype = GUINT32_TO_LE(data->devtype);
	out_data->data_type = data->type;

	list_item = data->prints;
	while (list_item) {
		item = list_item->data;
		out_item = (struct fpi_print_data_item_fp2 *)buf;
		out_item->length = GUINT32_TO_LE(item->length);
		/* FIXME: fp_print_data_item->data content is not endianess agnostic */
		memcpy(out_item->data, item->data, item->length);
		buf += sizeof(*out_item);
		buf += item->length;
		list_item = g_slist_next(list_item);
	}

221 222 223
	return buflen;
}

224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263
static struct fp_print_data *fpi_print_data_from_fp1_data(unsigned char *buf,
	size_t buflen)
{
	size_t print_data_len;
	struct fp_print_data *data;
	struct fp_print_data_item *item;
	struct fpi_print_data_fp2 *raw = (struct fpi_print_data_fp2 *) buf;

	print_data_len = buflen - sizeof(*raw);
	data = print_data_new(GUINT16_FROM_LE(raw->driver_id),
		GUINT32_FROM_LE(raw->devtype), raw->data_type);
	item = fpi_print_data_item_new(print_data_len);
	/* FIXME: fp_print_data->data content is not endianess agnostic */
	memcpy(item->data, raw->data, print_data_len);
	data->prints = g_slist_prepend(data->prints, item);

	return data;
}

static struct fp_print_data *fpi_print_data_from_fp2_data(unsigned char *buf,
	size_t buflen)
{
	size_t total_data_len, item_len;
	struct fp_print_data *data;
	struct fp_print_data_item *item;
	struct fpi_print_data_fp2 *raw = (struct fpi_print_data_fp2 *) buf;
	unsigned char *raw_buf;
	struct fpi_print_data_item_fp2 *raw_item;

	total_data_len = buflen - sizeof(*raw);
	data = print_data_new(GUINT16_FROM_LE(raw->driver_id),
		GUINT32_FROM_LE(raw->devtype), raw->data_type);
	raw_buf = raw->data;
	while (total_data_len) {
		if (total_data_len < sizeof(*raw_item))
			break;
		total_data_len -= sizeof(*raw_item);

		raw_item = (struct fpi_print_data_item_fp2 *)raw_buf;
		item_len = GUINT32_FROM_LE(raw_item->length);
264
		fp_dbg("item len %d, total_data_len %d", (int) item_len, (int) total_data_len);
265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288
		if (total_data_len < item_len) {
			fp_err("corrupted fingerprint data");
			break;
		}
		total_data_len -= item_len;

		item = fpi_print_data_item_new(item_len);
		/* FIXME: fp_print_data->data content is not endianess agnostic */
		memcpy(item->data, raw_item->data, item_len);
		data->prints = g_slist_prepend(data->prints, item);

		raw_buf += sizeof(*raw_item);
		raw_buf += item_len;
	}

	if (g_slist_length(data->prints) == 0) {
		fp_print_data_free(data);
		data = NULL;
	}

	return data;

}

289 290 291 292 293
/**
 * fp_print_data_from_data:
 * @buf: the data buffer
 * @buflen: the length of the buffer

Daniel Drake's avatar
Daniel Drake committed
294 295 296
 * Load a stored print from a data buffer. The contents of said buffer must
 * be the untouched contents of a buffer previously supplied to you by the
 * fp_print_data_get_data() function.
297 298
 *
 * Returns: the stored print represented by the data, or %NULL on error. Must
Daniel Drake's avatar
Daniel Drake committed
299 300
 * be freed with fp_print_data_free() after use.
 */
301 302 303
API_EXPORTED struct fp_print_data *fp_print_data_from_data(unsigned char *buf,
	size_t buflen)
{
304
	struct fpi_print_data_fp2 *raw = (struct fpi_print_data_fp2 *) buf;
305 306 307 308 309

	fp_dbg("buffer size %zd", buflen);
	if (buflen < sizeof(*raw))
		return NULL;

310 311 312 313 314
	if (strncmp(raw->prefix, "FP1", 3) == 0) {
		return fpi_print_data_from_fp1_data(buf, buflen);
	} else if (strncmp(raw->prefix, "FP2", 3) == 0) {
		return fpi_print_data_from_fp2_data(buf, buflen);
	} else {
315 316 317
		fp_dbg("bad header prefix");
	}

318
	return NULL;
319 320
}

Daniel Drake's avatar
Daniel Drake committed
321
static char *get_path_to_storedir(uint16_t driver_id, uint32_t devtype)
322 323 324 325 326 327 328 329 330 331
{
	char idstr[5];
	char devtypestr[9];

	g_snprintf(idstr, sizeof(idstr), "%04x", driver_id);
	g_snprintf(devtypestr, sizeof(devtypestr), "%08x", devtype);

	return g_build_filename(base_store, idstr, devtypestr, NULL);
}

Daniel Drake's avatar
Daniel Drake committed
332 333
static char *__get_path_to_print(uint16_t driver_id, uint32_t devtype,
	enum fp_finger finger)
334 335 336
{
	char *dirpath;
	char *path;
Daniel Drake's avatar
Daniel Drake committed
337 338 339
	char fingername[2];

	g_snprintf(fingername, 2, "%x", finger);
340

Daniel Drake's avatar
Daniel Drake committed
341 342
	dirpath = get_path_to_storedir(driver_id, devtype);
	path = g_build_filename(dirpath, fingername, NULL);
343 344 345 346
	g_free(dirpath);
	return path;
}

Daniel Drake's avatar
Daniel Drake committed
347 348 349 350 351
static char *get_path_to_print(struct fp_dev *dev, enum fp_finger finger)
{
	return __get_path_to_print(dev->drv->id, dev->devtype, finger);
}

352 353 354 355 356
/**
 * fp_print_data_save:
 * @data: the stored print to save to disk
 * @finger: the finger that this print corresponds to
 *
Daniel Drake's avatar
Daniel Drake committed
357 358 359 360 361 362 363 364 365 366
 * Saves a stored print to disk, assigned to a specific finger. Even though
 * you are limited to storing only the 10 human fingers, this is a
 * per-device-type limit. For example, you can store the users right index
 * finger from a DigitalPersona scanner, and you can also save the right index
 * finger from a UPEK scanner. When you later come to load the print, the right
 * one will be automatically selected.
 *
 * This function will unconditionally overwrite a fingerprint previously
 * saved for the same finger and device type. The print is saved in a hidden
 * directory beneath the current user's home directory.
367 368
 *
 * Returns: 0 on success, non-zero on error.
Daniel Drake's avatar
Daniel Drake committed
369
 */
370 371 372 373 374 375
API_EXPORTED int fp_print_data_save(struct fp_print_data *data,
	enum fp_finger finger)
{
	GError *err = NULL;
	char *path;
	char *dirpath;
376 377
	unsigned char *buf;
	size_t len;
378 379 380 381 382
	int r;

	if (!base_store)
		storage_setup();

Daniel Drake's avatar
Daniel Drake committed
383 384
	fp_dbg("save %s print from driver %04x", finger_num_to_str(finger),
		data->driver_id);
385 386 387 388
	len = fp_print_data_get_data(data, &buf);
	if (!len)
		return -ENOMEM;

Daniel Drake's avatar
Daniel Drake committed
389 390
	path = __get_path_to_print(data->driver_id, data->devtype, finger);
	dirpath = g_path_get_dirname(path);
391 392 393
	r = g_mkdir_with_parents(dirpath, DIR_PERMS);
	if (r < 0) {
		fp_err("couldn't create storage directory");
Daniel Drake's avatar
Daniel Drake committed
394
		g_free(path);
395 396 397 398 399
		g_free(dirpath);
		return r;
	}

	fp_dbg("saving to %s", path);
400 401
	g_file_set_contents(path, buf, len, &err);
	free(buf);
402 403 404 405
	g_free(dirpath);
	g_free(path);
	if (err) {
		r = err->code;
Daniel Drake's avatar
Daniel Drake committed
406
		fp_err("save failed: %s", err->message);
407
		g_error_free(err);
408
		/* FIXME interpret error codes */
409 410 411 412 413 414
		return r;
	}

	return 0;
}

Daniel Drake's avatar
Daniel Drake committed
415 416 417
gboolean fpi_print_data_compatible(uint16_t driver_id1, uint32_t devtype1,
	enum fp_print_data_type type1, uint16_t driver_id2, uint32_t devtype2,
	enum fp_print_data_type type2)
418
{
Daniel Drake's avatar
Daniel Drake committed
419 420
	if (driver_id1 != driver_id2) {
		fp_dbg("driver ID mismatch: %02x vs %02x", driver_id1, driver_id2);
421 422 423
		return FALSE;
	}

Daniel Drake's avatar
Daniel Drake committed
424 425
	if (devtype1 != devtype2) {
		fp_dbg("devtype mismatch: %04x vs %04x", devtype1, devtype2);
426 427 428
		return FALSE;
	}

Daniel Drake's avatar
Daniel Drake committed
429 430
	if (type1 != type2) {
		fp_dbg("type mismatch: %d vs %d", type1, type2);
431 432 433 434 435 436
		return FALSE;
	}

	return TRUE;
}

Daniel Drake's avatar
Daniel Drake committed
437
static int load_from_file(char *path, struct fp_print_data **data)
438 439 440 441
{
	gsize length;
	gchar *contents;
	GError *err = NULL;
Daniel Drake's avatar
Daniel Drake committed
442
	struct fp_print_data *fdata;
443 444 445 446 447

	fp_dbg("from %s", path);
	g_file_get_contents(path, &contents, &length, &err);
	if (err) {
		int r = err->code;
Daniel Drake's avatar
Daniel Drake committed
448
		fp_err("%s load failed: %s", path, err->message);
449
		g_error_free(err);
450
		/* FIXME interpret more error codes */
451 452 453 454 455 456
		if (r == G_FILE_ERROR_NOENT)
			return -ENOENT;
		else
			return r;
	}

Daniel Drake's avatar
Daniel Drake committed
457
	fdata = fp_print_data_from_data(contents, length);
458
	g_free(contents);
Daniel Drake's avatar
Daniel Drake committed
459 460 461
	if (!fdata)
		return -EIO;
	*data = fdata;
Daniel Drake's avatar
Daniel Drake committed
462 463 464
	return 0;
}

465 466 467 468 469 470 471
/**
 * fp_print_data_load:
 * @dev: the device you are loading the print for
 * @finger: the finger of the file you are loading
 * @data: output location to put the corresponding stored print. Must be
 * freed with fp_print_data_free() after use.

Daniel Drake's avatar
Daniel Drake committed
472 473 474 475 476 477 478
 * Loads a previously stored print from disk. The print must have been saved
 * earlier using the fp_print_data_save() function.
 *
 * A return code of -ENOENT indicates that the fingerprint requested could not
 * be found. Other error codes (both positive and negative) are possible for
 * obscure error conditions (e.g. corruption).
 *
479
 * Returns: 0 on success, non-zero on error
Daniel Drake's avatar
Daniel Drake committed
480
 */
Daniel Drake's avatar
Daniel Drake committed
481 482 483 484 485 486
API_EXPORTED int fp_print_data_load(struct fp_dev *dev,
	enum fp_finger finger, struct fp_print_data **data)
{
	gchar *path;
	struct fp_print_data *fdata;
	int r;
487

Daniel Drake's avatar
Daniel Drake committed
488 489 490 491 492 493 494 495 496 497
	if (!base_store)
		storage_setup();

	path = get_path_to_print(dev, finger);
	r = load_from_file(path, &fdata);
	g_free(path);
	if (r)
		return r;

	if (!fp_dev_supports_print_data(dev, fdata)) {
498
		fp_err("print data is not compatible!");
Daniel Drake's avatar
Daniel Drake committed
499
		fp_print_data_free(fdata);
500 501 502
		return -EINVAL;
	}

503 504 505 506
	*data = fdata;
	return 0;
}

507 508 509 510 511
/**
 * fp_print_data_delete:
 * @dev: the device that the print belongs to
 * @finger: the finger of the file you are deleting

512
 * Removes a stored print from disk previously saved with fp_print_data_save().
513 514
 *
 * Returns: 0 on success, negative on error
515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531
 */
API_EXPORTED int fp_print_data_delete(struct fp_dev *dev,
	enum fp_finger finger)
{
	int r;
	gchar *path = get_path_to_print(dev, finger);

	fp_dbg("remove finger %d at %s", finger, path);
	r = g_unlink(path);
	g_free(path);
	if (r < 0)
		fp_dbg("unlink failed with error %d", r);

	/* FIXME: cleanup empty directory */
	return r;
}

532 533 534 535 536 537 538
/**
 * fp_print_data_from_dscv_print:
 * @print: the discovered print
 * @data: output location to point to the corresponding stored print. Must
 * be freed with fp_print_data_free() after use.

 * Attempts to load a stored print based on a #fp_dscv_print
539
 * discovered print record.
Daniel Drake's avatar
Daniel Drake committed
540 541 542 543 544
 *
 * A return code of -ENOENT indicates that the file referred to by the
 * discovered print could not be found. Other error codes (both positive and
 * negative) are possible for obscure error conditions (e.g. corruption).
 *
545
 * Returns: 0 on success, non-zero on error.
546 547
 *
 * Deprecated: Do not use.
Daniel Drake's avatar
Daniel Drake committed
548
 */
Daniel Drake's avatar
Daniel Drake committed
549 550 551 552 553 554
API_EXPORTED int fp_print_data_from_dscv_print(struct fp_dscv_print *print,
	struct fp_print_data **data)
{
	return load_from_file(print->path, data);
}

555 556 557 558
/**
 * fp_print_data_free:
 * @data: the stored print to destroy. If NULL, function simply returns.
 *
Daniel Drake's avatar
Daniel Drake committed
559 560
 * Frees a stored print. Must be called when you are finished using the print.
 */
561 562
API_EXPORTED void fp_print_data_free(struct fp_print_data *data)
{
563 564
	if (data)
		g_slist_free_full(data->prints, (GDestroyNotify)fpi_print_data_item_free);
565 566 567
	g_free(data);
}

568 569 570 571 572
/**
 * fp_print_data_get_driver_id:
 * @data: the stored print

 * Gets the [driver ID](advanced-topics.html#driver_id) for a stored print. The driver ID
Daniel Drake's avatar
Daniel Drake committed
573 574
 * indicates which driver the print originally came from. The print is
 * only usable with a device controlled by that driver.
575 576
 *
 * Returns: the driver ID of the driver compatible with the print
Daniel Drake's avatar
Daniel Drake committed
577
 */
578 579 580 581 582
API_EXPORTED uint16_t fp_print_data_get_driver_id(struct fp_print_data *data)
{
	return data->driver_id;
}

583 584 585 586 587
/**
 * fp_print_data_get_devtype:
 * @data: the stored print

 * Gets the [devtype](advanced-topics.html#device-types) for a stored print. The devtype represents
Daniel Drake's avatar
Daniel Drake committed
588
 * which type of device under the parent driver is compatible with the print.
589 590
 *
 * Returns: the devtype of the device range compatible with the print
Daniel Drake's avatar
Daniel Drake committed
591
 */
592 593 594 595
API_EXPORTED uint32_t fp_print_data_get_devtype(struct fp_print_data *data)
{
	return data->devtype;
}
Daniel Drake's avatar
Daniel Drake committed
596

597 598
/**
 * SECTION:dscv_print
599
 * @title: Print discovery (deprecated)
600
 * @short_description: Print discovery functions
601 602
 *
 * The [stored print](libfprint-Stored-prints.html) documentation detailed a simple API
Daniel Drake's avatar
Daniel Drake committed
603 604 605 606 607 608 609 610 611 612
 * for storing per-device prints for a single user, namely
 * fp_print_data_save(). It also detailed a load function,
 * fp_print_data_load(), but usage of this function is limited to scenarios
 * where you know which device you would like to use, and you know which
 * finger you are looking to verify.
 *
 * In other cases, it would be more useful to be able to enumerate all
 * previously saved prints, potentially even before device discovery. These
 * functions are designed to offer this functionality to you.
 *
613
 * Discovered prints are stored in a #fp_dscv_print structure, and you
Daniel Drake's avatar
Daniel Drake committed
614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630
 * can use functions documented below to access some information about these
 * prints. You can determine if a discovered print appears to be compatible
 * with a device using functions such as fp_dscv_dev_supports_dscv_print() and
 * fp_dev_supports_dscv_print().
 *
 * When you are ready to use the print, you can load it into memory in the form
 * of a stored print by using the fp_print_data_from_dscv_print() function.
 *
 * You may have noticed the use of the word "appears" in the above paragraphs.
 * libfprint performs print discovery simply by examining the file and
 * directory structure of libfprint's private data store. It does not examine
 * the actual prints themselves. Just because a print has been discovered
 * and appears to be compatible with a certain device does not necessarily mean
 * that it is usable; when you come to load or use it, under unusual
 * circumstances it may turn out that the print is corrupt or not for the
 * device that it appeared to be. Also, it is possible that the print may have
 * been deleted by the time you come to load it.
631 632 633 634
 *
 * Note that this portion of the library is deprecated. All that it offers is
 * already implementable using publicly available functions, and its usage is
 * unnecessarily restrictive in terms of how it stores data.
Daniel Drake's avatar
Daniel Drake committed
635 636
 */

Daniel Drake's avatar
Daniel Drake committed
637 638 639 640 641 642 643 644 645 646 647 648 649 650
static GSList *scan_dev_store_dir(char *devpath, uint16_t driver_id,
	uint32_t devtype, GSList *list)
{
	GError *err = NULL;
	const gchar *ent;
	struct fp_dscv_print *print;

	GDir *dir = g_dir_open(devpath, 0, &err);
	if (!dir) {
		fp_err("opendir %s failed: %s", devpath, err->message);
		g_error_free(err);
		return list;
	}

Daniel Drake's avatar
Daniel Drake committed
651
	while ((ent = g_dir_read_name(dir))) {
Daniel Drake's avatar
Daniel Drake committed
652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691
		/* ent is an 1 hex character fp_finger code */
		guint64 val;
		enum fp_finger finger;
		gchar *endptr;

		if (*ent == 0 || strlen(ent) != 1)
			continue;

		val = g_ascii_strtoull(ent, &endptr, 16);
		if (endptr == ent || !FP_FINGER_IS_VALID(val)) {
			fp_dbg("skipping print file %s", ent);
			continue;
		}

		finger = (enum fp_finger) val;
		print = g_malloc(sizeof(*print));
		print->driver_id = driver_id;
		print->devtype = devtype;
		print->path = g_build_filename(devpath, ent, NULL);
		print->finger = finger;
		list = g_slist_prepend(list, print);
	}

	g_dir_close(dir);
	return list;
}

static GSList *scan_driver_store_dir(char *drvpath, uint16_t driver_id,
	GSList *list)
{
	GError *err = NULL;
	const gchar *ent;

	GDir *dir = g_dir_open(drvpath, 0, &err);
	if (!dir) {
		fp_err("opendir %s failed: %s", drvpath, err->message);
		g_error_free(err);
		return list;
	}

Daniel Drake's avatar
Daniel Drake committed
692
	while ((ent = g_dir_read_name(dir))) {
Daniel Drake's avatar
Daniel Drake committed
693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717
		/* ent is an 8 hex character devtype */
		guint64 val;
		uint32_t devtype;
		gchar *endptr;
		gchar *path;

		if (*ent == 0 || strlen(ent) != 8)
			continue;

		val = g_ascii_strtoull(ent, &endptr, 16);
		if (endptr == ent) {
			fp_dbg("skipping devtype %s", ent);
			continue;
		}

		devtype = (uint32_t) val;
		path = g_build_filename(drvpath, ent, NULL);
		list = scan_dev_store_dir(path, driver_id, devtype, list);
		g_free(path);
	}

	g_dir_close(dir);
	return list;
}

718 719 720
/**
 * fp_discover_prints:
 *
Daniel Drake's avatar
Daniel Drake committed
721 722
 * Scans the users home directory and returns a list of prints that were
 * previously saved using fp_print_data_save().
723 724
 *
 * Returns: a %NULL-terminated list of discovered prints, must be freed with
Daniel Drake's avatar
Daniel Drake committed
725
 * fp_dscv_prints_free() after use.
726 727
 *
 * Deprecated: Do not use.
Daniel Drake's avatar
Daniel Drake committed
728
 */
Daniel Drake's avatar
Daniel Drake committed
729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749
API_EXPORTED struct fp_dscv_print **fp_discover_prints(void)
{
	GDir *dir;
	const gchar *ent;
	GError *err = NULL;
	GSList *tmplist = NULL;
	GSList *elem;
	unsigned int tmplist_len;
	struct fp_dscv_print **list;
	unsigned int i;

	if (!base_store)
		storage_setup();

	dir = g_dir_open(base_store, 0, &err);
	if (!dir) {
		fp_err("opendir %s failed: %s", base_store, err->message);
		g_error_free(err);
		return NULL;
	}

Daniel Drake's avatar
Daniel Drake committed
750
	while ((ent = g_dir_read_name(dir))) {
Daniel Drake's avatar
Daniel Drake committed
751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783
		/* ent is a 4 hex digit driver_id */
		gchar *endptr;
		gchar *path;
		guint64 val;
		uint16_t driver_id;

		if (*ent == 0 || strlen(ent) != 4)
			continue;

		val = g_ascii_strtoull(ent, &endptr, 16);
		if (endptr == ent) {
			fp_dbg("skipping drv id %s", ent);
			continue;
		}

		driver_id = (uint16_t) val;
		path = g_build_filename(base_store, ent, NULL);
		tmplist = scan_driver_store_dir(path, driver_id, tmplist);
		g_free(path);
	}

	g_dir_close(dir);
	tmplist_len = g_slist_length(tmplist);
	list = g_malloc(sizeof(*list) * (tmplist_len + 1));
	elem = tmplist;
	for (i = 0; i < tmplist_len; i++, elem = g_slist_next(elem))
		list[i] = elem->data;
	list[tmplist_len] = NULL; /* NULL-terminate */

	g_slist_free(tmplist);
	return list;
}

784 785 786 787 788
/**
 * fp_dscv_prints_free:
 * @prints: the list of discovered prints. If NULL, function simply
 * returns.
 *
Daniel Drake's avatar
Daniel Drake committed
789 790 791
 * Frees a list of discovered prints. This function also frees the discovered
 * prints themselves, so make sure you do not use any discovered prints
 * after calling this function.
792 793
 *
 * Deprecated: Do not use.
Daniel Drake's avatar
Daniel Drake committed
794
 */
Daniel Drake's avatar
Daniel Drake committed
795 796 797 798 799 800 801 802
API_EXPORTED void fp_dscv_prints_free(struct fp_dscv_print **prints)
{
	int i;
	struct fp_dscv_print *print;

	if (!prints)
		return;

Daniel Drake's avatar
Daniel Drake committed
803
	for (i = 0; (print = prints[i]); i++) {
Daniel Drake's avatar
Daniel Drake committed
804 805 806 807 808 809 810
		if (print)
			g_free(print->path);
		g_free(print);
	}
	g_free(prints);
}

811 812 813 814 815
/**
 * fp_dscv_print_get_driver_id:
 * @print: the discovered print
 *
 * Gets the [driver ID](advanced-topics.html#driver_id) for a discovered print. The driver ID
Daniel Drake's avatar
Daniel Drake committed
816 817
 * indicates which driver the print originally came from. The print is only
 * usable with a device controlled by that driver.
818 819
 *
 * Returns: the driver ID of the driver compatible with the print
820 821
 *
 * Deprecated: Do not use.
Daniel Drake's avatar
Daniel Drake committed
822
 */
Daniel Drake's avatar
Daniel Drake committed
823 824 825 826 827
API_EXPORTED uint16_t fp_dscv_print_get_driver_id(struct fp_dscv_print *print)
{
	return print->driver_id;
}

828 829 830 831 832
/**
 * fp_dscv_print_get_devtype:
 * @print: the discovered print
 *
 * Gets the [devtype](advanced-topics.html#device-types) for a discovered print. The devtype
Daniel Drake's avatar
Daniel Drake committed
833 834
 * represents which type of device under the parent driver is compatible
 * with the print.
835 836
 *
 * Returns: the devtype of the device range compatible with the print
837 838
 *
 * Deprecated: Do not use.
Daniel Drake's avatar
Daniel Drake committed
839
 */
Daniel Drake's avatar
Daniel Drake committed
840 841 842 843 844
API_EXPORTED uint32_t fp_dscv_print_get_devtype(struct fp_dscv_print *print)
{
	return print->devtype;
}

845 846 847 848
/**
 * fp_dscv_print_get_finger:
 * @print: discovered print
 *
Daniel Drake's avatar
Daniel Drake committed
849
 * Gets the finger code for a discovered print.
850 851
 *
 * Returns: a finger code from #fp_finger
852 853
 *
 * Deprecated: Do not use.
Daniel Drake's avatar
Daniel Drake committed
854
 */
Daniel Drake's avatar
Daniel Drake committed
855 856 857 858
API_EXPORTED enum fp_finger fp_dscv_print_get_finger(struct fp_dscv_print *print)
{
	return print->finger;
}
Daniel Drake's avatar
Daniel Drake committed
859

860 861 862 863
/**
 * fp_dscv_print_delete:
 * @print: the discovered print to remove from disk
 *
864 865 866 867
 * Removes a discovered print from disk. After successful return of this
 * function, functions such as fp_dscv_print_get_finger() will continue to
 * operate as before, however calling fp_print_data_from_dscv_print() will
 * fail for obvious reasons.
868 869
 *
 * Returns: 0 on success, negative on error
870 871
 *
 * Deprecated: Do not use.
872 873 874 875 876 877 878 879 880 881 882 883 884
 */
API_EXPORTED int fp_dscv_print_delete(struct fp_dscv_print *print)
{
	int r;
	fp_dbg("remove at %s", print->path);
	r = g_unlink(print->path);
	if (r < 0)
		fp_dbg("unlink failed with error %d", r);

	/* FIXME: cleanup empty directory */
	return r;
}