fpi-data.c 23.8 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");
394
		free(buf);
Daniel Drake's avatar
Daniel Drake committed
395
		g_free(path);
396 397 398 399 400
		g_free(dirpath);
		return r;
	}

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

	return 0;
}

Daniel Drake's avatar
Daniel Drake committed
416 417 418
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)
419
{
Daniel Drake's avatar
Daniel Drake committed
420 421
	if (driver_id1 != driver_id2) {
		fp_dbg("driver ID mismatch: %02x vs %02x", driver_id1, driver_id2);
422 423 424
		return FALSE;
	}

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

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

	return TRUE;
}

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

	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
449
		fp_err("%s load failed: %s", path, err->message);
450
		g_error_free(err);
451
		/* FIXME interpret more error codes */
452 453 454 455 456 457
		if (r == G_FILE_ERROR_NOENT)
			return -ENOENT;
		else
			return r;
	}

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

466 467 468 469 470 471 472
/**
 * 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
473 474 475 476 477 478 479
 * 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).
 *
480
 * Returns: 0 on success, non-zero on error
Daniel Drake's avatar
Daniel Drake committed
481
 */
Daniel Drake's avatar
Daniel Drake committed
482 483 484 485 486 487
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;
488

Daniel Drake's avatar
Daniel Drake committed
489 490 491 492 493 494 495 496 497 498
	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)) {
499
		fp_err("print data is not compatible!");
Daniel Drake's avatar
Daniel Drake committed
500
		fp_print_data_free(fdata);
501 502 503
		return -EINVAL;
	}

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

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

513
 * Removes a stored print from disk previously saved with fp_print_data_save().
514 515
 *
 * Returns: 0 on success, negative on error
516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532
 */
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;
}

533 534 535 536 537 538 539
/**
 * 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
540
 * discovered print record.
Daniel Drake's avatar
Daniel Drake committed
541 542 543 544 545
 *
 * 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).
 *
546
 * Returns: 0 on success, non-zero on error.
547 548
 *
 * Deprecated: Do not use.
Daniel Drake's avatar
Daniel Drake committed
549
 */
Daniel Drake's avatar
Daniel Drake committed
550 551 552 553 554 555
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);
}

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

569 570 571 572 573
/**
 * 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
574 575
 * indicates which driver the print originally came from. The print is
 * only usable with a device controlled by that driver.
576 577
 *
 * Returns: the driver ID of the driver compatible with the print
Daniel Drake's avatar
Daniel Drake committed
578
 */
579 580 581 582 583
API_EXPORTED uint16_t fp_print_data_get_driver_id(struct fp_print_data *data)
{
	return data->driver_id;
}

584 585 586 587 588
/**
 * 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
589
 * which type of device under the parent driver is compatible with the print.
590 591
 *
 * Returns: the devtype of the device range compatible with the print
Daniel Drake's avatar
Daniel Drake committed
592
 */
593 594 595 596
API_EXPORTED uint32_t fp_print_data_get_devtype(struct fp_print_data *data)
{
	return data->devtype;
}
Daniel Drake's avatar
Daniel Drake committed
597

598 599
/**
 * SECTION:dscv_print
600
 * @title: Print discovery (deprecated)
601
 * @short_description: Print discovery functions
602 603
 *
 * The [stored print](libfprint-Stored-prints.html) documentation detailed a simple API
Daniel Drake's avatar
Daniel Drake committed
604 605 606 607 608 609 610 611 612 613
 * 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.
 *
614
 * Discovered prints are stored in a #fp_dscv_print structure, and you
Daniel Drake's avatar
Daniel Drake committed
615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631
 * 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.
632 633 634 635
 *
 * 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
636 637
 */

Daniel Drake's avatar
Daniel Drake committed
638 639 640 641 642 643 644 645 646 647 648 649 650 651
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
652
	while ((ent = g_dir_read_name(dir))) {
Daniel Drake's avatar
Daniel Drake committed
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 692
		/* 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
693
	while ((ent = g_dir_read_name(dir))) {
Daniel Drake's avatar
Daniel Drake committed
694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718
		/* 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;
}

719 720 721
/**
 * fp_discover_prints:
 *
Daniel Drake's avatar
Daniel Drake committed
722 723
 * Scans the users home directory and returns a list of prints that were
 * previously saved using fp_print_data_save().
724 725
 *
 * Returns: a %NULL-terminated list of discovered prints, must be freed with
Daniel Drake's avatar
Daniel Drake committed
726
 * fp_dscv_prints_free() after use.
727 728
 *
 * Deprecated: Do not use.
Daniel Drake's avatar
Daniel Drake committed
729
 */
Daniel Drake's avatar
Daniel Drake committed
730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750
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
751
	while ((ent = g_dir_read_name(dir))) {
Daniel Drake's avatar
Daniel Drake committed
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 784
		/* 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;
}

785 786 787 788 789
/**
 * fp_dscv_prints_free:
 * @prints: the list of discovered prints. If NULL, function simply
 * returns.
 *
Daniel Drake's avatar
Daniel Drake committed
790 791 792
 * 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.
793 794
 *
 * Deprecated: Do not use.
Daniel Drake's avatar
Daniel Drake committed
795
 */
Daniel Drake's avatar
Daniel Drake committed
796 797 798 799 800 801 802 803
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
804
	for (i = 0; (print = prints[i]); i++) {
Daniel Drake's avatar
Daniel Drake committed
805 806 807 808 809 810 811
		if (print)
			g_free(print->path);
		g_free(print);
	}
	g_free(prints);
}

812 813 814 815 816
/**
 * 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
817 818
 * indicates which driver the print originally came from. The print is only
 * usable with a device controlled by that driver.
819 820
 *
 * Returns: the driver ID of the driver compatible with the print
821 822
 *
 * Deprecated: Do not use.
Daniel Drake's avatar
Daniel Drake committed
823
 */
Daniel Drake's avatar
Daniel Drake committed
824 825 826 827 828
API_EXPORTED uint16_t fp_dscv_print_get_driver_id(struct fp_dscv_print *print)
{
	return print->driver_id;
}

829 830 831 832 833
/**
 * 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
834 835
 * represents which type of device under the parent driver is compatible
 * with the print.
836 837
 *
 * Returns: the devtype of the device range compatible with the print
838 839
 *
 * Deprecated: Do not use.
Daniel Drake's avatar
Daniel Drake committed
840
 */
Daniel Drake's avatar
Daniel Drake committed
841 842 843 844 845
API_EXPORTED uint32_t fp_dscv_print_get_devtype(struct fp_dscv_print *print)
{
	return print->devtype;
}

846 847 848 849
/**
 * fp_dscv_print_get_finger:
 * @print: discovered print
 *
Daniel Drake's avatar
Daniel Drake committed
850
 * Gets the finger code for a discovered print.
851 852
 *
 * Returns: a finger code from #fp_finger
853 854
 *
 * Deprecated: Do not use.
Daniel Drake's avatar
Daniel Drake committed
855
 */
Daniel Drake's avatar
Daniel Drake committed
856 857 858 859
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
860

861 862 863 864
/**
 * fp_dscv_print_delete:
 * @print: the discovered print to remove from disk
 *
865 866 867 868
 * 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.
869 870
 *
 * Returns: 0 on success, negative on error
871 872
 *
 * Deprecated: Do not use.
873 874 875 876 877 878 879 880 881 882 883 884 885
 */
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;
}