Subversion Repositories Kolibri OS

Rev

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