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