Subversion Repositories Kolibri OS

Rev

Rev 9952 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
9837 turbocat 1
#include 
2
#include 
3
#include 
4
#include 
5
#include 
6
#include 
7
#include 
8
#include 
9
#include 
10
#include 
11
#ifndef __MINGW32__
12
#include 
13
#include 
14
#include 
15
#include 
16
#ifdef HAVE_GLOB_H
17
#include 
18
#endif
19
#else
20
#include 
21
#include 
22
#endif
23
#ifdef WITH_LIBARCHIVE
24
#include 
25
/* For backward compatibility. */
26
#if ARCHIVE_VERSION_NUMBER < 3001000
27
#define archive_read_free(...) \
28
	archive_read_finish(__VA_ARGS__)
29
#define archive_read_support_filter_all(...) \
30
	archive_read_support_compression_all(__VA_ARGS__)
31
#endif
32
#endif
33
#include "system.h"
34
 
35
#ifdef __MINGW32__
36
#define mkdir(a, b) mkdir(a)
37
#if MAX_PATH < PATH_MAX
38
#error MAX_PATH < PATH_MAX. You should use MAX_PATH.
39
#endif
40
#endif
41
 
42
static const char *fopen_mode(unsigned int mode)
43
{
44
	static const char *modes[4][2] = {
45
		{ "ab", "a" },
46
		{ "w+b", "w+" },
47
		{ "rb", "r" },
48
		{ NULL, NULL }
49
	};
50
	const char *(*cmode)[2] = &modes[0];
51
 
52
	if (!(mode & DGEN_APPEND)) {
53
		++cmode;
54
		if (!(mode & DGEN_WRITE)) {
55
			++cmode;
56
			if (!(mode & DGEN_READ))
57
				++cmode;
58
		}
59
	}
60
	return (*cmode)[(!!(mode & DGEN_TEXT))];
61
}
62
 
63
enum path_type {
64
	PATH_TYPE_UNSPECIFIED,
65
	PATH_TYPE_RELATIVE,
66
	PATH_TYPE_ABSOLUTE
67
};
68
 
69
#ifdef __MINGW32__
70
 
71
/**
72
 * Check whether a path is absolute or relative.
73
 *
74
 * Examples:
75
 * /foo/bar, \\foo\\bar, c:/foo/bar are absolute,
76
 * ./foo/bar, ., .., are relative.
77
 *
78
 * @param[in] path Path to parse.
79
 * @param len Length of path.
80
 * @return Path type (PATH_TYPE_ABSOLUTE, PATH_TYPE_RELATIVE or
81
 * PATH_TYPE_UNSPECIFIED).
82
 */
83
enum path_type path_type(const char *path, size_t len)
84
{
85
	if ((len == 0) || (path[0] == '\0'))
86
		return PATH_TYPE_UNSPECIFIED;
87
	if ((path[0] == '\\') || (path[0] == '/'))
88
		return PATH_TYPE_ABSOLUTE;
89
	if ((path[0] == '.') &&
90
	    (((len == 1) ||
91
	      (path[1] == '\0') || (path[1] == '\\') || (path[1] == '/')) ||
92
	     ((path[1] == '.') &&
93
	      ((len == 2) ||
94
	       (path[2] == '\0') || (path[2] == '\\') || (path[2] == '/')))))
95
		return PATH_TYPE_RELATIVE;
96
	do {
97
		if (*(++path) == ':')
98
			return PATH_TYPE_ABSOLUTE;
99
		--len;
100
	}
101
	while ((len) && (*path != '\0') && (*path != '\\') && (*path != '/'));
102
	return PATH_TYPE_UNSPECIFIED;
103
}
104
 
105
#else /* __MINGW32__ */
106
 
107
/**
108
 * Check whether a path is absolute or relative.
109
 *
110
 * Examples:
111
 * /foo/bar, \\foo\\bar are absolute,
112
 * ./foo/bar, ., .., are relative.
113
 *
114
 * @param[in] path Path to parse.
115
 * @param len Length of path.
116
 * @return Path type (PATH_TYPE_ABSOLUTE, PATH_TYPE_RELATIVE or
117
 * PATH_TYPE_UNSPECIFIED).
118
 */
119
enum path_type path_type(const char *path, size_t len)
120
{
121
	if ((len == 0) || (path[0] == '\0'))
122
		return PATH_TYPE_UNSPECIFIED;
123
	if (path[0] == '/')
124
		return PATH_TYPE_ABSOLUTE;
125
	if ((path[0] == '.') &&
126
	    (((len == 1) || (path[1] == '\0') || (path[1] == '/')) ||
127
	     ((path[1] == '.') &&
128
	      ((len == 2) || (path[2] == '\0') || (path[2] == '/')))))
129
		return PATH_TYPE_RELATIVE;
130
	return PATH_TYPE_UNSPECIFIED;
131
}
132
 
133
#endif /* __MINGW32__ */
134
 
135
/**
136
 * Return user's home directory.
137
 * The returned string doesn't have a trailing '/' and must be freed using
138
 * free() (unless "buf" is provided).
139
 *
140
 * @param[in,out] buf Used to store path in. If NULL, memory is allocated.
141
 * @param[in,out] size Size of "buf" when provided, then the returned path
142
 * size.
143
 * @return User's home directory (either as "buf" or a new buffer),
144
 * NULL in case of error.
145
 */
146
char *dgen_userdir(char *buf, size_t *size)
147
{
148
	char *path;
149
	size_t sz_dir;
150
	size_t sz;
151
#if !defined __MINGW32__ && !defined _KOLIBRI
152
	struct passwd *pwd = getpwuid(geteuid());
153
 
154
	if ((pwd == NULL) || (pwd->pw_dir == NULL))
155
		return NULL;
156
	sz_dir = strlen(pwd->pw_dir);
9970 turbocat 157
#elif defined _KOLIBRI
158
	char *kos_home = getenv("HOME");
159
	if (!kos_home)
160
		return NULL;
161
	sz_dir = strlen(kos_home);
9837 turbocat 162
#endif
163
	if (buf != NULL) {
164
		sz = *size;
165
#if	defined __MINGW32__ || defined _KOLIBRI
166
		if (sz < PATH_MAX)
167
			return NULL;
168
#else
169
		if (sz < (sz_dir + 1))
170
			return NULL;
171
#endif
172
		path = buf;
173
	}
174
	else {
175
#if defined __MINGW32__ || defined _KOLIBRI
176
		sz = PATH_MAX;
177
#else
178
		sz = (sz_dir + 1);
179
#endif
180
		if ((path = malloc(sz)) == NULL)
181
			return NULL;
182
	}
183
#ifndef __MINGW32__
184
	#ifdef _KOLIBRI
9970 turbocat 185
	strncpy(path, kos_home, sz_dir);
9837 turbocat 186
	#else
187
	strncpy(path, pwd->pw_dir, sz_dir);
188
	#endif
189
#else
190
	if (SHGetFolderPath(NULL, (CSIDL_PROFILE | CSIDL_FLAG_CREATE),
191
			    0, 0, path) != S_OK) {
192
		if (buf == NULL)
193
			free(path);
194
		return NULL;
195
	}
196
	sz_dir = strlen(path);
197
	if (sz < (sz_dir + 1)) {
198
		if (buf == NULL)
199
			free(path);
200
		return NULL;
201
	}
202
#endif
203
	path[sz_dir] = '\0';
204
	if (size != NULL)
205
		*size = sz_dir;
206
	return path;
207
}
208
 
209
/**
210
 * Return DGen's home directory with an optional subdirectory (or file).
211
 * The returned string doesn't have a trailing '/' and must be freed using
212
 * free() (unless "buf" is provided).
213
 *
214
 * @param[in,out] buf Buffer to store result in. If NULL, memory is allocated.
215
 * @param[in,out] size Size of "buf" when provided, then the returned path
216
 * size.
217
 * @param[in] sub NUL-terminated string to append to the path.
218
 * @return DGen's home directory (either as "buf" or a new buffer),
219
 * NULL in case of error.
220
 */
221
char *dgen_dir(char *buf, size_t *size, const char *sub)
222
{
223
	char *path;
224
	size_t sz_dir;
225
	size_t sz_sub;
226
	const size_t sz_bd = strlen(DGEN_BASEDIR);
227
	size_t sz;
228
#ifndef __MINGW32__
229
	#ifndef _KOLIBRI
230
	struct passwd *pwd = getpwuid(geteuid());
231
	if ((pwd == NULL) || (pwd->pw_dir == NULL))
232
		return NULL;
233
	sz_dir = strlen(pwd->pw_dir);
234
	#else
9970 turbocat 235
	char *kos_home = getenv("HOME");
236
	if (!kos_home)
237
		return NULL;
238
	sz_dir = strlen(kos_home);
9837 turbocat 239
	#endif
240
#endif
241
 
242
	if (sub != NULL)
243
		sz_sub = strlen(sub);
244
	else
245
		sz_sub = 0;
246
	if (buf != NULL) {
247
		sz = *size;
248
#if defined(__MINGW32__) || defined(_KOLIBRI)
249
		if (sz < PATH_MAX)
250
			return NULL;
251
#else
252
		if (sz < (sz_dir + 1 + sz_bd + !!sz_sub + sz_sub + 1))
253
			return NULL;
254
#endif
255
		path = buf;
256
	}
257
	else {
258
#if defined(__MINGW32__) || defined(_KOLIBRI)
259
		sz = PATH_MAX;
260
#else
261
		sz = (sz_dir + 1 + sz_bd + !!sz_sub + sz_sub + 1);
262
#endif
263
		if ((path = malloc(sz)) == NULL)
264
			return NULL;
265
	}
266
#ifndef __MINGW32__
267
	#ifndef _KOLIBRI
268
	strncpy(path, pwd->pw_dir, sz_dir);
269
	#else
9970 turbocat 270
	strncpy(path, kos_home, sz_dir);
9837 turbocat 271
	#endif
272
#else
273
	if (SHGetFolderPath(NULL, (CSIDL_APPDATA | CSIDL_FLAG_CREATE),
274
			    0, 0, path) != S_OK) {
275
		if (buf == NULL)
276
			free(path);
277
		return NULL;
278
	}
279
	sz_dir = strlen(path);
280
	if (sz < (sz_dir + 1 + sz_bd + !!sz_sub + sz_sub + 1)) {
281
		if (buf == NULL)
282
			free(path);
283
		return NULL;
284
	}
285
#endif
286
	path[(sz_dir++)] = DGEN_DIRSEP[0];
287
	memcpy(&path[sz_dir], DGEN_BASEDIR, sz_bd);
288
	sz_dir += sz_bd;
289
	if (sz_sub) {
290
		path[(sz_dir++)] = DGEN_DIRSEP[0];
291
		memcpy(&path[sz_dir], sub, sz_sub);
292
		sz_dir += sz_sub;
293
	}
294
	path[sz_dir] = '\0';
295
	if (size != NULL)
296
		*size = sz_dir;
297
	return path;
298
}
299
 
300
/**
301
 * Open a file relative to DGen's home directory (when "relative" is NULL or
302
 * path_type(relative) returns PATH_TYPE_UNSPECIFIED) and create the directory
303
 * hierarchy if necessary, unless the file name is already relative to
304
 * something or found in the current directory if mode contains DGEN_CURRENT.
305
 *
306
 * @param[in] relative Subdirectory to look in.
307
 * @param[in] file File name to open.
308
 * @param mode Mode flags to use (DGEN_READ, DGEN_WRITE and others).
309
 * @return File pointer, or NULL in case of error.
310
 * @see dgen_freopen()
311
 * @see system.h
312
 */
313
FILE *dgen_fopen(const char *relative, const char *file, unsigned int mode)
314
{
315
	return dgen_freopen(relative, file, mode, NULL);
316
}
317
 
318
/**
319
 * @see dgen_fopen()
320
 */
321
FILE *dgen_freopen(const char *relative, const char *file, unsigned int mode,
322
		   FILE *f)
323
{
324
	size_t size;
325
	size_t file_size;
326
	char *tmp;
327
	int e = errno;
328
	const char *fmode = fopen_mode(mode);
329
	char *path = NULL;
330
 
331
	if ((file == NULL) || (file[0] == '\0') || (fmode == NULL))
332
		goto error;
333
	/*
334
	  Try to open the file in the current directory if DGEN_CURRENT
335
	  is specified.
336
	*/
337
	if (mode & DGEN_CURRENT) {
338
		FILE *fd;
339
 
340
		if (f == NULL)
341
			fd = fopen(file, fmode);
342
		else
343
			fd = freopen(file, fmode, f);
344
		if (fd != NULL)
345
			return fd;
346
	}
347
	if (path_type(file, ~0u) != PATH_TYPE_UNSPECIFIED)
348
		size = 0;
349
	else if ((relative == NULL) ||
350
		 (path_type(relative, ~0u) == PATH_TYPE_UNSPECIFIED)) {
351
		if ((path = dgen_dir(NULL, &size, relative)) == NULL)
352
			goto error;
353
	}
354
	else {
355
		if ((path = strdup(relative)) == NULL)
356
			goto error;
357
		size = strlen(path);
358
	}
9970 turbocat 359
 
9837 turbocat 360
	if ((mode & (DGEN_WRITE | DGEN_APPEND)) && (path != NULL))
361
		mkdir(path, 0777); /* XXX make that recursive */
9970 turbocat 362
 
9837 turbocat 363
	file_size = strlen(file);
364
	if ((tmp = realloc(path, (size + !!size + file_size + 1))) == NULL)
365
		goto error;
366
	path = tmp;
367
	if (size)
368
		path[(size++)] = DGEN_DIRSEP[0];
369
	memcpy(&path[size], file, file_size);
370
	size += file_size;
371
	path[size] = '\0';
372
	errno = e;
373
	if (f == NULL)
374
		f = fopen(path, fmode);
375
	else
376
		f = freopen(path, fmode, f);
377
	e = errno;
378
	free(path);
379
	errno = e;
380
	return f;
381
error:
382
	free(path);
383
	errno = EACCES;
384
	return NULL;
385
}
386
 
387
/**
388
 * Return the base name in path, like basename() but without allocating
389
 * anything nor modifying the "path" argument.
390
 *
391
 * @param[in] path Path to extract the last component from.
392
 * @return Last component from "path".
393
 */
394
const char *dgen_basename(const char *path)
395
{
396
	char *tmp;
397
 
398
	while ((tmp = strpbrk(path, DGEN_DIRSEP)) != NULL)
399
		path = (tmp + 1);
400
	return path;
401
}
402
 
403
#define CHUNK_SIZE BUFSIZ
404
 
405
struct chunk {
406
	size_t size;
407
	struct chunk *next;
408
	struct chunk *prev;
409
	uint8_t data[];
410
};
411
 
412
/**
413
 * Unload pointer returned by load().
414
 *
415
 * @param[in] data Pointer to unload.
416
 */
417
void unload(uint8_t *data)
418
{
419
	struct chunk *chunk = ((struct chunk *)data - 1);
420
 
421
	assert(chunk->next == chunk);
422
	assert(chunk->prev == chunk);
423
	free(chunk);
424
}
425
 
426
#ifdef HAVE_FTELLO
427
#define FTELL(f) ftello(f)
428
#define FSEEK(f, o, w) fseeko((f), (o), (w))
429
#define FOFFT off_t
430
#else
431
#define FTELL(f) ftell(f)
432
#define FSEEK(f, o, w) fseek((f), (o), (w))
433
#define FOFFT long
434
#endif
435
 
436
/**
437
 * Call this when you're done with your file.
438
 *
439
 * @param[in,out] context Context returned by load().
440
 */
441
void load_finish(void **context)
442
{
443
#ifdef WITH_LIBARCHIVE
444
	struct archive *archive = *context;
445
 
446
	if (archive != NULL)
447
		archive_read_free(archive);
448
#endif
449
	*context = NULL;
450
}
451
 
452
/**
453
 * Return the remaining file size from the current file offset.
454
 *
455
 * @param[in] file File pointer.
456
 */
457
static size_t load_size(FILE *file)
458
{
459
	FOFFT old = FTELL(file);
460
	FOFFT pos;
461
	size_t ret = 0;
462
 
463
	if ((old == (FOFFT)-1) ||
464
	    (FSEEK(file, 0, SEEK_END) == -1))
465
		return 0;
466
	if (((pos = FTELL(file)) != (FOFFT)-1) && (pos >= old))
467
		ret = (size_t)(pos - old);
468
	FSEEK(file, old, SEEK_SET);
469
	return ret;
470
}
471
 
472
/**
473
 * Allocate a buffer and stuff the file inside using transparent decompression
474
 * if libarchive is available. If file_size is non-NULL, store the final size
475
 * there. If max_size is nonzero, refuse to load anything larger.
476
 * In case the returned value is NULL, errno should contain the error.
477
 *
478
 * If an error is returned but errno is 0, EOF has been reached.
479
 *
480
 * @param[in,out] context On first call of load() this should point to NULL.
481
 * @param[out] file_size Final size.
482
 * @param[in] file File pointer to load data from.
483
 * @param max_size If nonzero, refuse to load anything larger.
484
 * @return Buffer containing loaded data.
485
 */
486
uint8_t *load(void **context,
487
	      size_t *file_size, FILE *file, size_t max_size)
488
{
489
	size_t pos;
490
	size_t size = 0;
491
	struct chunk *chunk;
492
	struct chunk head = { 0, &head, &head };
493
	size_t chunk_size = load_size(file);
494
	int error = 0;
495
#ifdef WITH_LIBARCHIVE
496
	struct archive *archive = *context;
497
	struct archive_entry *archive_entry;
498
 
499
	if (archive != NULL)
500
		goto init_ok;
501
	archive = archive_read_new();
502
	*context = archive;
503
	if (archive == NULL) {
504
		error = ENOMEM;
505
		goto error;
506
	}
507
	archive_read_support_filter_all(archive);
508
	archive_read_support_format_all(archive);
509
	archive_read_support_format_raw(archive);
510
	if (archive_read_open_FILE(archive, file) != ARCHIVE_OK) {
511
		error = EIO;
512
		goto error;
513
	}
514
init_ok:
515
	switch (archive_read_next_header(archive, &archive_entry)) {
516
	case ARCHIVE_OK:
517
		break;
518
	case ARCHIVE_EOF:
519
		error = 0;
520
		goto error;
521
	default:
522
		error = EIO;
523
		goto error;
524
	}
525
#else
526
	*context = (void *)0xffff;
527
#endif
528
	if (chunk_size == 0)
529
		chunk_size = CHUNK_SIZE;
530
	else if ((max_size != 0) && (chunk_size > max_size))
531
		chunk_size = max_size;
532
	while (1) {
533
		pos = 0;
534
		chunk = malloc(sizeof(*chunk) + chunk_size);
535
		if (chunk == NULL) {
536
			error = errno;
537
			goto error;
538
		}
539
		chunk->size = chunk_size;
540
		chunk->next = &head;
541
		chunk->prev = head.prev;
542
		chunk->prev->next = chunk;
543
		head.prev = chunk;
544
		do {
545
			size_t i;
546
#ifdef WITH_LIBARCHIVE
547
			ssize_t j;
548
 
549
			j = archive_read_data(archive, &chunk->data[pos],
550
					      (chunk->size - pos));
551
			/*
552
			  Don't bother with ARCHIVE_WARN and ARCHIVE_RETRY,
553
			  consider any negative value an error.
554
			*/
555
			if (j < 0) {
556
				error = EIO;
557
				goto error;
558
			}
559
			i = (size_t)j;
560
#else
561
			i = fread(&chunk->data[pos], 1, (chunk->size - pos),
562
				  file);
563
#endif
564
			if (i == 0) {
565
				chunk->size = pos;
566
#ifndef WITH_LIBARCHIVE
567
				if (ferror(file)) {
568
					error = EIO;
569
					goto error;
570
				}
571
				assert(feof(file));
572
#endif
573
				goto process;
574
			}
575
			pos += i;
576
			size += i;
577
			if ((max_size != 0) && (size > max_size)) {
578
				error = EFBIG;
579
				goto error;
580
			}
581
		}
582
		while (pos != chunk->size);
583
		chunk_size = CHUNK_SIZE;
584
	}
585
process:
586
	chunk = realloc(head.next, (sizeof(*chunk) + size));
587
	if (chunk == NULL) {
588
		error = errno;
589
		goto error;
590
	}
591
	chunk->next->prev = chunk;
592
	head.next = chunk;
593
	pos = chunk->size;
594
	chunk->size = size;
595
	chunk = chunk->next;
596
	while (chunk != &head) {
597
		struct chunk *next = chunk->next;
598
 
599
		memcpy(&head.next->data[pos], chunk->data, chunk->size);
600
		pos += chunk->size;
601
		chunk->next->prev = chunk->prev;
602
		chunk->prev->next = chunk->next;
603
		free(chunk);
604
		chunk = next;
605
	}
606
	chunk = head.next;
607
	chunk->prev = chunk;
608
	chunk->next = chunk;
609
	if (file_size != NULL)
610
		*file_size = chunk->size;
611
	return chunk->data;
612
error:
613
#ifdef WITH_LIBARCHIVE
614
	load_finish(context);
615
#endif
616
	chunk = head.next;
617
	while (chunk != &head) {
618
		struct chunk *next = chunk->next;
619
 
620
		free(chunk);
621
		chunk = next;
622
	}
623
	errno = error;
624
	return NULL;
625
}
626
 
627
/**
628
 * Free NULL-terminated list of strings and set source pointer to NULL.
629
 * This function can skip a given number of indices (starting from 0)
630
 * which won't be freed.
631
 *
632
 * @param[in,out] pppc Pointer to an array of strings.
633
 * @param skip Number of indices to skip in *pppc[].
634
 */
635
static void free_pppc(char ***pppc, size_t skip)
636
{
637
	char **p = *pppc;
638
	size_t i;
639
 
640
	if (p == NULL)
641
		return;
642
	*pppc = NULL;
643
	for (i = 0; (p[i] != NULL); ++i) {
644
		if (skip == 0)
645
			free(p[i]);
646
		else
647
			--skip;
648
	}
649
	free(p);
650
}
651
 
652
/**
653
 * Return a list of path names that match "len" characters of "path" on the
654
 * file system, or NULL if none was found or if an error occured.
655
 *
656
 * @param[in] path Path name to match.
657
 * @param len Number of characters in "path" to match.
658
 * @return List of matching path names or NULL.
659
 */
660
static char **complete_path_simple(const char *path, size_t len)
661
{
662
	size_t rlen;
663
	const char *cpl;
664
	char *root;
665
	struct dirent *dent;
666
	DIR *dir;
667
	char **ret = NULL;
668
	size_t ret_size = 256;
669
	size_t ret_used = 0;
670
	struct stat st;
671
 
672
	if ((rlen = strlen(path)) < len)
673
		len = rlen;
674
	cpl = path;
675
	while (((root = strpbrk(cpl, DGEN_DIRSEP)) != NULL) &&
676
	       (root < (path + len)))
677
		cpl = (root + 1);
678
	rlen = (cpl - path);
679
	len -= rlen;
680
	if (rlen == 0) {
681
		path = "." DGEN_DIRSEP;
682
		rlen = 2;
683
	}
684
	if ((root = malloc(rlen + 1)) == NULL)
685
		return NULL;
686
	memcpy(root, path, rlen);
687
	root[rlen] = '\0';
688
	if (((dir = opendir(root)) == NULL) ||
689
	    ((ret = malloc(sizeof(*ret) * ret_size)) == NULL))
690
		goto error;
691
	ret[(ret_used++)] = NULL;
692
	while ((dent = readdir(dir)) != NULL) {
693
		size_t i;
694
		char *t;
695
 
696
		if ((cpl[0] != '\0') && (strncmp(cpl, dent->d_name, len)))
697
			continue;
698
		/* Remove "." and ".." entries. */
699
		if ((dent->d_name[0] == '.') &&
700
		    ((dent->d_name[1] == '\0') ||
701
		     ((dent->d_name[1] == '.') && (dent->d_name[2] == '\0'))))
702
			continue;
703
		if (ret_used == ret_size) {
704
			char **rt;
705
 
706
			ret_size *= 2;
707
			if ((rt = realloc(ret,
708
					  (sizeof(*rt) * ret_size))) == NULL)
709
				break;
710
			ret = rt;
711
		}
712
		i = strlen(dent->d_name);
713
		/* Allocate one extra char in case it's a directory. */
714
		if ((t = malloc(rlen + i + 1 + 1)) == NULL)
715
			break;
716
		memcpy(t, root, rlen);
717
		memcpy(&t[rlen], dent->d_name, i);
718
		t[(rlen + i)] = '\0';
719
		if ((stat(t, &st) != -1) && (S_ISDIR(st.st_mode))) {
720
			t[(rlen + (i++))] = DGEN_DIRSEP[0];
721
			t[(rlen + i)] = '\0';
722
		}
723
		for (i = 0; (ret[i] != NULL); ++i)
724
			if (strcmp(dent->d_name, &ret[i][rlen]) < 0)
725
				break;
726
		memmove(&ret[(i + 1)], &ret[i],
727
			(sizeof(*ret) * (ret_used - i)));
728
		ret[i] = t;
729
		++ret_used;
730
	}
731
	closedir(dir);
732
	free(root);
733
	if (ret[0] != NULL)
734
		return ret;
735
	free(ret);
736
	return NULL;
737
error:
738
	if (dir != NULL)
739
		closedir(dir);
740
	free(root);
741
	if (ret != NULL) {
742
		while (*ret != NULL)
743
			free(*(ret++));
744
		free(ret);
745
	}
9970 turbocat 746
 
9837 turbocat 747
	return NULL;
748
}
749
 
9952 turbocat 750
#if defined(HAVE_GLOB_H) && !defined(__MINGW32__)
9837 turbocat 751
 
752
#define COMPLETE_USERDIR_TILDE 0x01
753
#define COMPLETE_USERDIR_EXACT 0x02
754
#define COMPLETE_USERDIR_ALL 0x04
755
 
756
/**
757
 * Return the list of home directories that match "len" characters of a
758
 * user's name ("prefix").
759
 * COMPLETE_USERDIR_TILDE - Instead of directories, the returned strings are
760
 * tilde-prefixed user names.
761
 * COMPLETE_USERDIR_EXACT - Prefix must exactly match a user name.
762
 * COMPLETE_USERDIR_ALL - When prefix length is 0, return all user names
763
 * instead of the current user only.
764
 *
765
 * @param[in] prefix Path name to match.
766
 * @param len Number of characters to match in "path".
767
 * @return List of home directories that match "len" characters of "prefix".
768
 */
769
static char **complete_userdir(const char *prefix, size_t len, int flags)
770
{
771
	char **ret = NULL;
772
	char *s;
773
	struct passwd *pwd;
774
	size_t n;
775
	size_t i;
776
	int tilde = !!(flags & COMPLETE_USERDIR_TILDE);
777
	int exact = !!(flags & COMPLETE_USERDIR_EXACT);
778
	int all = !!(flags & COMPLETE_USERDIR_ALL);
779
 
780
	setpwent();
781
	if ((!all) && (len == 0)) {
782
		if (((pwd = getpwuid(geteuid())) == NULL) ||
783
		    ((ret = calloc(2, sizeof(ret[0]))) == NULL))
784
			goto err;
785
		if (tilde)
786
			s = pwd->pw_name;
787
		else
788
			s = pwd->pw_dir;
789
		i = strlen(s);
790
		if ((ret[0] = calloc((tilde + i + 1),
791
				     sizeof(*ret[0]))) == NULL)
792
			goto err;
793
		if (tilde)
794
			ret[0][0] = '~';
795
		memcpy(&ret[0][tilde], s, i);
796
		ret[0][(tilde + i)] = '\0';
797
		goto end;
798
	}
799
	n = 64;
800
	if ((ret = calloc(n, sizeof(ret[0]))) == NULL)
801
		goto err;
802
	i = 0;
803
	while ((pwd = getpwent()) != NULL) {
804
		size_t j;
805
 
806
		if (exact) {
807
			if (strncmp(pwd->pw_name, prefix,
808
				    strlen(pwd->pw_name)))
809
				continue;
810
		}
811
		else if (strncmp(pwd->pw_name, prefix, len))
812
			continue;
813
		if (i == (n - 1)) {
814
			char **tmp;
815
 
816
			n += 64;
817
			if ((tmp = realloc(ret, (sizeof(ret[0]) * n))) == NULL)
818
				goto end;
819
			ret = tmp;
820
		}
821
		if (tilde)
822
			s = pwd->pw_name;
823
		else
824
			s = pwd->pw_dir;
825
		j = strlen(s);
826
		if ((ret[i] = calloc((tilde + j + 1),
827
				     sizeof(*ret[0]))) == NULL)
828
			break;
829
		if (tilde)
830
			ret[i][0] = '~';
831
		memcpy(&ret[i][tilde], s, j);
832
		ret[i][(tilde + j)] = '\0';
833
		++i;
834
	}
835
	if (i == 0) {
836
		free(ret);
837
		ret = NULL;
838
	}
839
end:
840
	endpwent();
841
	return ret;
842
err:
843
	endpwent();
844
	free_pppc(&ret, 0);
845
	return NULL;
846
}
847
 
848
/**
849
 * Return a list of pathnames that match "len" characters of "prefix" on the
850
 * file system, or NULL if none was found or if an error occured. This is done
851
 * using glob() in order to handle wildcard characters in "prefix".
852
 *
853
 * When "prefix" isn't explicitly relative nor absolute, if "relative" is
854
 * non-NULL, then the path will be completed as if "prefix" was a subdirectory
855
 * of "relative". If "relative" is NULL, DGen's home directory will be used.
856
 *
857
 * If "relative" isn't explicitly relative nor absolute, it will be considered
858
 * a subdirectory of DGen's home directory.
859
 *
860
 * @param[in] prefix Path name to match.
861
 * @param len Number of characters to match in "path".
862
 * @param[in] relative If non-NULL, consider path relative to this.
863
 * @return List of path names that match "len" characters of "prefix".
864
 */
865
char **complete_path(const char *prefix, size_t len, const char *relative)
866
{
867
	char *s;
868
	char **ret;
869
	size_t i;
870
	glob_t g;
871
	size_t strip;
872
 
873
	(void)complete_path_simple; /* unused */
874
	if ((i = strlen(prefix)) < len)
875
		len = i;
876
	else
877
		i = len;
878
	if (((s = strchr(prefix, '/')) != NULL) && ((i = (s - prefix)) > len))
879
		i = len;
880
	if ((len == 0) ||
881
	    ((prefix[0] != '~') &&
882
	     (strncmp(prefix, ".", i)) &&
883
	     (strncmp(prefix, "..", i)))) {
884
		size_t n;
885
 
886
		if ((relative == NULL) ||
887
		    (path_type(relative, ~0u) == PATH_TYPE_UNSPECIFIED)) {
888
			char *x = dgen_dir(NULL, &n, relative);
889
 
890
			if ((x == NULL) ||
891
			    ((s = realloc(x, (n + 1 + len + 2))) == NULL)) {
892
				free(x);
893
				return NULL;
894
			}
895
		}
896
		else {
897
			n = strlen(relative);
898
			if ((s = malloc(n + 1 + len + 2)) == NULL)
899
				return NULL;
900
			memcpy(s, relative, n);
901
		}
902
		s[(n++)] = '/';
903
		strip = n;
904
		memcpy(&s[n], prefix, len);
905
		len += n;
906
		s[(len++)] = '*';
907
		s[len] = '\0';
908
	}
909
	else if (prefix[0] == '~') {
910
		char **ud;
911
		size_t n;
912
 
913
		if (s == NULL)
914
			return complete_userdir(&prefix[1], (i - 1),
915
						(COMPLETE_USERDIR_TILDE |
916
						 COMPLETE_USERDIR_ALL));
917
		ud = complete_userdir(&prefix[1], (i - 1),
918
				      COMPLETE_USERDIR_EXACT);
919
		if (ud == NULL)
920
			goto no_userdir;
921
		n = strlen(ud[0]);
922
		if ((s = realloc(ud[0], (n + (len - i) + 2))) == NULL) {
923
			free_pppc(&ud, 0);
924
			goto no_userdir;
925
		}
926
		free_pppc(&ud, 1);
927
		len -= i;
928
		strip = 0;
929
		memcpy(&s[n], &prefix[i], len);
930
		len += n;
931
		s[(len++)] = '*';
932
		s[len] = '\0';
933
	}
934
	else {
935
	no_userdir:
936
		if ((s = malloc(len + 2)) == NULL)
937
			return NULL;
938
		memcpy(s, prefix, len);
939
		s[(len++)] = '*';
940
		s[len] = '\0';
941
		strip = 0;
942
	}
943
	switch (glob(s, (GLOB_MARK | GLOB_NOESCAPE), NULL, &g)) {
944
	case 0:
945
		break;
946
	case GLOB_NOSPACE:
947
	case GLOB_ABORTED:
948
	case GLOB_NOMATCH:
949
	default:
950
		free(s);
951
		return NULL;
952
	}
953
	free(s);
954
	if ((ret = calloc((g.gl_pathc + 1), sizeof(ret[0]))) == NULL)
955
		goto err;
956
	for (i = 0; (g.gl_pathv[i] != NULL); ++i) {
957
		size_t j;
958
 
959
		len = strlen(g.gl_pathv[i]);
960
		if (strip > len)
961
			break;
962
		j = (len - strip);
963
		if ((ret[i] = calloc((j + 1), sizeof(ret[i][0]))) == NULL)
964
			break;
965
		memcpy(ret[i], &(g.gl_pathv[i][strip]), j);
966
		ret[i][j] = '\0';
967
	}
968
	if (i == 0)
969
		goto err;
970
	globfree(&g);
971
	return ret;
972
err:
973
	globfree(&g);
974
	free_pppc(&ret, 0);
975
	return NULL;
976
}
977
 
978
#else /* defined(HAVE_GLOB_H) && !defined(__MINGW32__) */
979
 
980
/**
981
 * Return a list of pathnames that match "len" characters of "prefix" on the
982
 * file system, or NULL if none was found or if an error occured.
983
 *
984
 * When "prefix" isn't explicitly relative nor absolute, if "relative" is
985
 * non-NULL, then the path will be completed as if "prefix" was a subdirectory
986
 * of "relative". If "relative" is NULL, DGen's home directory will be used.
987
 *
988
 * If "relative" isn't explicitly relative nor absolute, it will be considered
989
 * a subdirectory of DGen's home directory.
990
 *
991
 * @param[in] prefix Path name to match.
992
 * @param len Number of characters to match in "path".
993
 * @param[in] relative If non-NULL, consider path relative to this.
994
 * @return List of path names that match "len" characters of "prefix".
995
 */
996
char **complete_path(const char *prefix, size_t len, const char *relative)
997
{
998
	char *s;
999
	char **ret;
1000
	size_t i;
1001
	size_t n;
1002
	size_t strip;
1003
	enum path_type pt;
1004
 
1005
	if ((i = strlen(prefix)) < len)
1006
		len = i;
1007
	if (((pt = path_type(prefix, len)) == PATH_TYPE_ABSOLUTE) ||
1008
	    (pt == PATH_TYPE_RELATIVE))
1009
		return complete_path_simple(prefix, len);
1010
	if ((len != 0) && (prefix[0] == '~') &&
1011
	    ((len == 1) ||
1012
	     (prefix[1] == '\0') ||
1013
	     (strpbrk(prefix, DGEN_DIRSEP) == &prefix[1]))) {
1014
		char *x = dgen_userdir(NULL, &n);
1015
 
1016
		if ((x == NULL) ||
1017
		    ((s = realloc(x, (n + 1 + 2 + len + 1))) == NULL)) {
1018
			free(x);
1019
			return NULL;
1020
		}
1021
		++prefix;
1022
		--len;
1023
		strip = 0;
1024
	}
1025
	else if ((relative == NULL) ||
1026
		 (path_type(relative, ~0u) == PATH_TYPE_UNSPECIFIED)) {
1027
		char *x = dgen_dir(NULL, &n, relative);
1028
 
1029
		if ((x == NULL) ||
1030
		    ((s = realloc(x, (n + 1 + len + 1))) == NULL)) {
1031
			free(x);
1032
			return NULL;
1033
		}
1034
		strip = (n + 1);
1035
	}
1036
	else {
1037
		n = strlen(relative);
1038
		if ((s = malloc(n + 1 + len + 1)) == NULL)
1039
			return NULL;
1040
		memcpy(s, relative, n);
1041
		strip = (n + 1);
1042
	}
1043
	s[(n++)] = DGEN_DIRSEP[0];
1044
	memcpy(&s[n], prefix, len);
1045
	len += n;
1046
	s[len] = '\0';
1047
	ret = complete_path_simple(s, len);
1048
	free(s);
1049
	if (ret == NULL)
1050
		return NULL;
1051
	if (strip == 0)
1052
		return ret;
1053
	for (i = 0; (ret[i] != NULL); ++i)
1054
		memmove(ret[i], &ret[i][strip],
1055
			((strlen(ret[i]) - strip) + 1));
1056
	return ret;
1057
}
1058
 
1059
#endif /* defined(HAVE_GLOB_H) && !defined(__MINGW32__) */
1060
 
1061
/**
1062
 * Free return value of complete*() functions.
1063
 *
1064
 * @param[in, out] cp Buffer to pass to free_pppc().
1065
 */
1066
void complete_path_free(char **cp)
1067
{
1068
	free_pppc(&cp, 0);
1069
}
1070
 
1071
/**
1072
 * Create an escaped version of a string.
1073
 * When not NULL, "pos" refers to an offset in string "src". It is updated
1074
 * with its new offset value in the escaped string.
1075
 *
1076
 * @param[in] src String to escape.
1077
 * @param size Number of characters from "src" to process.
1078
 * @param flags BACKSLASHIFY_* flags.
1079
 * @param[in, out] pos Offset in string "src" to update.
1080
 * @return Escaped version of "src", NULL on error.
1081
 */
1082
char *backslashify(const uint8_t *src, size_t size, unsigned int flags,
1083
		   size_t *pos)
1084
{
1085
	char *dst = NULL;
1086
	char *tmp;
1087
	size_t i;
1088
	size_t j;
1089
	char buf[5];
1090
 
1091
again:
1092
	for (i = 0, j = 0; (i < size); ++i) {
1093
		switch (src[i]) {
1094
		case '\a':
1095
			tmp = "\\a";
1096
			break;
1097
		case '\b':
1098
			tmp = "\\b";
1099
			break;
1100
		case '\f':
1101
			tmp = "\\f";
1102
			break;
1103
		case '\n':
1104
			tmp = "\\n";
1105
			break;
1106
		case '\r':
1107
			tmp = "\\r";
1108
			break;
1109
		case '\t':
1110
			tmp = "\\t";
1111
			break;
1112
		case '\v':
1113
			tmp = "\\v";
1114
			break;
1115
		case '\'':
1116
			if (flags & BACKSLASHIFY_NOQUOTES)
1117
				goto noquotes;
1118
			tmp = "\\'";
1119
			break;
1120
		case '"':
1121
			if (flags & BACKSLASHIFY_NOQUOTES)
1122
				goto noquotes;
1123
			tmp = "\\\"";
1124
			break;
1125
		case ' ':
1126
			if (flags & BACKSLASHIFY_NOQUOTES)
1127
				tmp = " ";
1128
			else
1129
				tmp = "\\ ";
1130
			break;
1131
		case '\0':
1132
			tmp = "\\0";
1133
			break;
1134
		case '\\':
1135
			if (flags & BACKSLASHIFY_NOQUOTES)
1136
				goto noquotes;
1137
			tmp = "\\\\";
1138
			break;
1139
		default:
1140
		noquotes:
1141
			tmp = buf;
1142
			if (isgraph(src[i])) {
1143
				tmp[0] = src[i];
1144
				tmp[1] = '\0';
1145
				break;
1146
			}
1147
			tmp[0] = '\\';
1148
			tmp[1] = 'x';
1149
			snprintf(&tmp[2], 3, "%02x", src[i]);
1150
			break;
1151
		}
1152
		if (dst != NULL)
1153
			strncpy(&dst[j], tmp, strlen(tmp));
1154
		if ((pos != NULL) && (i == *pos)) {
1155
			*pos = j;
1156
			pos = NULL;
1157
		}
1158
		j += strlen(tmp);
1159
	}
1160
	if ((pos != NULL) && (i == *pos)) {
1161
		*pos = j;
1162
		pos = NULL;
1163
	}
1164
	if (dst == NULL) {
1165
		dst = malloc(j + 1);
1166
		if (dst == NULL)
1167
			return NULL;
1168
		dst[j] = '\0';
1169
		goto again;
1170
	}
1171
	return dst;
1172
}
1173
 
1174
/**
1175
 * Convert a UTF-8 character to its 32 bit representation.
1176
 * Return the number of valid bytes for this character.
1177
 * On error, u32 is set to (uint32_t)-1.
1178
 *
1179
 * @param[out] u32 Converted character, (uint32_t)-1 on error.
1180
 * @param[in] u8 Multibyte character to convert.
1181
 * @return Number of bytes read.
1182
 */
1183
size_t utf8u32(uint32_t *u32, const uint8_t *u8)
1184
{
1185
	static const uint8_t fb[] = {
1186
		/* first byte: mask, expected value, size */
1187
		0x80, 0x00, 1,
1188
		0xe0, 0xc0, 2,
1189
		0xf0, 0xe0, 3,
1190
		0xf8, 0xf0, 4,
1191
		0xfc, 0xf8, 5,
1192
		0xfe, 0xfc, 6,
1193
		0xff, 0x00, 0
1194
	};
1195
	const uint8_t *s = fb;
1196
	size_t i = 0;
1197
	size_t rem;
1198
	uint32_t ret;
1199
 
1200
	while ((*u8 & s[0]) != s[1])
1201
		s += 3;
1202
	rem = s[2];
1203
	if (!rem)
1204
		goto error;
1205
	ret = (*u8 & ~s[0]);
1206
	while (++i != rem) {
1207
		++u8;
1208
		if ((*u8 & 0xc0) != 0x80)
1209
			goto error;
1210
		ret <<= 6;
1211
		ret |= (*u8 & ~0xc0);
1212
	}
1213
	if (((ret & ~0x07ff) == 0xd800) ||
1214
	    ((ret & ~0x0001) == 0xfffe))
1215
		goto error;
1216
	*u32 = ret;
1217
	return i;
1218
error:
1219
	*u32 = (uint32_t)-1;
1220
	return i;
1221
}
1222
 
1223
/**
1224
 * The opposite of utf8u32().
1225
 *
1226
 * @param[out] u8 Converted character.
1227
 * @param u32 Character to convert.
1228
 * @return Number of characters written to "u8", 0 on error.
1229
 */
1230
size_t utf32u8(uint8_t *u8, uint32_t u32)
1231
{
1232
	size_t l;
1233
	size_t i;
1234
	uint8_t fb;
1235
	uint32_t u;
1236
 
1237
	if ((u32 & 0x80000000) ||
1238
	    ((u32 & ~0x07ff) == 0xd800) ||
1239
	    ((u32 & ~0x0001) == 0xfffe))
1240
		return 0;
1241
	if (u32 < 0x80) {
1242
		if (u8 != NULL)
1243
			*u8 = u32;
1244
		return 1;
1245
	}
1246
	for (l = 0, u = u32; (u & ~0x3c); ++l)
1247
		u >>= 6;
1248
	if (u8 == NULL)
1249
		return l;
1250
	for (i = l, fb = 0; (--i); u32 >>= 6, fb >>= 1, fb |= 0xc0)
1251
		u8[i] = (0x80 | (u32 & 0x3f));
1252
	u8[0] = (fb | u32);
1253
	return l;
1254
}
1255
 
1256
/**
1257
 * Look for the longest common prefix between a string and an array
1258
 * of strings while ignoring case.
1259
 *
1260
 * @param[in] str String to compare argv entries to.
1261
 * @param[in] argv NULL-terminated array of prefixes to match.
1262
 * @return Index in argv or -1 if nothing matches.
1263
 */
1264
int prefix_casematch(const char *str, const char *argv[])
1265
{
1266
	unsigned int i;
1267
	size_t ret_len = 0;
1268
	int ret = -1;
1269
 
1270
	for (i = 0; (argv[i] != NULL); ++i) {
1271
		size_t len = strlen(argv[i]);
1272
 
1273
		if ((len < ret_len) ||
1274
		    (strncasecmp(str, argv[i], len)))
1275
			continue;
1276
		ret_len = len;
1277
		ret = i;
1278
	}
1279
	return ret;
1280
}
1281
 
1282
/**
1283
 * Read number from initial portion of a string and convert it.
1284
 *
1285
 * @param[in] str String to read from.
1286
 * @param[out] num If not NULL, stores the converted number.
1287
 * @return Length of the number in str, 0 on error.
1288
 */
1289
size_t prefix_getuint(const char *str, unsigned int *num)
1290
{
1291
	size_t len = 0;
1292
	unsigned int ret = 0;
1293
 
1294
	while (isdigit(str[len])) {
1295
		ret *= 10;
1296
		ret += (str[len] - '0');
1297
		++len;
1298
	}
1299
	if (len == 0)
1300
		return 0;
1301
	if (num != NULL)
1302
		*num = ret;
1303
	return len;
1304
}