2 * Copyright (C) 2008 Kristian Høgsberg <krh@redhat.com>
3 * Copyright (C) 2008 Red Hat, Inc
4 * Copyright (C) 2009, 2011, 2012, 2014, 2016 J. Ali Harlow <ali@juiblex.co.uk>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
25 #include <sys/types.h>
44 #include "types/types.h"
45 #include "razor-internal.h"
51 #define strcmp0(s1, s2) ((s1) && (s2) ? strcmp(s1, s2) : \
52 (s1) ? 1 : (s2) ? -1 : 0)
54 #define OPEN_FILE_USED (1U<<0)
55 #define OPEN_FILE_MMAPPED (1U<<1)
63 struct array open_files = { 0, };
65 void *razor_file_get_contents(const char *filename, size_t *length, int private,
66 struct razor_error **error)
73 struct open_file *of, *ofend;
75 fd = open(filename, O_RDONLY | O_BINARY);
77 razor_set_error_posix(error, filename);
81 if (fstat(fd, &st) < 0) {
82 razor_set_error_posix(error, filename);
89 ofend = open_files.data + open_files.size;
90 for (of = open_files.data; of < ofend; of++)
91 if (!(of->flags & OPEN_FILE_USED))
94 of = array_add(&open_files, sizeof *of);
100 addr = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
101 if (addr == MAP_FAILED)
104 of->flags = OPEN_FILE_USED | OPEN_FILE_MMAPPED;
106 #endif /* HAVE_SYS_MMAN_H */
108 addr = malloc(st.st_size);
110 of->flags = OPEN_FILE_USED;
112 while(nb < st.st_size) {
113 res = read(fd, addr + nb, st.st_size - nb);
115 razor_set_error_posix(error, filename);
123 razor_set_error(error, RAZOR_POSIX_ERROR, ENOMEM, NULL,
124 "Not enough memory");
129 of->length = st.st_size;
134 int razor_file_free_contents(void *addr, size_t length)
139 struct open_file *of, *ofend;
141 ofend = open_files.data + open_files.size;
142 for (of = open_files.data; of < ofend; of++)
143 if ((of->flags & OPEN_FILE_USED) && of->addr == addr)
151 mmapped = of->flags & OPEN_FILE_MMAPPED;
153 of->flags &= ~OPEN_FILE_USED;
155 for (of = open_files.data; of < ofend; of++)
156 if (of->flags & OPEN_FILE_USED)
160 array_release(&open_files);
161 array_init(&open_files);
166 return munmap(addr, length);
173 int razor_file_mkdir(const char *path, mode_t mode, struct razor_error **error)
178 retval = mkdir(path, mode);
182 * Ignore the case of a pre-existing directory and give
183 * an explicit error message if there is something other
184 * than a directory already at path.
187 if (code != EEXIST || stat(path, &buf))
188 razor_set_error(error, RAZOR_POSIX_ERROR, code, path,
190 else if (!S_ISDIR(buf.st_mode))
191 razor_set_error(error, RAZOR_POSIX_ERROR, code, path,
198 int razor_file_unlink(const char *path, struct razor_error **error)
202 retval = unlink(path);
205 razor_set_error_posix(error, path);
210 int razor_file_open(const char *path, int flags, mode_t mode,
211 struct razor_error **error)
215 retval = open(path, flags, mode);
218 razor_set_error_posix(error, path);
223 int razor_file_move(const char *path, const char *dest,
224 struct razor_error **error)
229 wchar_t *oldbuf, *newbuf;
230 const DWORD flags = MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING;
232 newbuf = razor_utf8_to_utf16(dest, -1);
233 oldbuf = razor_utf8_to_utf16(path, -1);
236 * Passing MOVEFILE_REPLACE_EXISTING to MoveFileEx() will
237 * cover every case we care about _except_ replacing an empty
238 * directory with a file. Calling RemoveDirectory() will deal
239 * with this case while having no effect in all other cases.
241 (void)RemoveDirectoryW(newbuf);
243 if (!MoveFileExW(oldbuf, newbuf, flags)) {
244 razor_set_error_mswin(error, newbuf, GetLastError());
254 if (rename(path, dest)) {
257 if (access(path, F_OK) < 0)
261 razor_set_error(error, RAZOR_POSIX_ERROR, code, object,
272 static char *absolute_path(const char *path)
275 char *result, *subpath, *p, *s, *t;
277 result = realpath(path, NULL);
279 if (!result && errno == ENOENT) {
285 result = strdup("/");
290 subpath = realpath(p, NULL);
294 len = strlen(subpath);
295 result = malloc(len + strlen(s) + 1);
296 memcpy(result, subpath, len);
297 strcpy(result + len, s);
300 } else if (errno != ENOENT)
309 result = realpath(".", NULL);
318 int razor_file_is_directory(const char *path, struct razor_error **error)
322 if (stat(path, &st) < 0) {
323 razor_set_error_posix(error, path);
327 return !!S_ISDIR(st.st_mode);
330 char *razor_file_mkdtemp_near(const char *path, const char *template,
331 struct razor_error **error)
336 if (path[0]=='\\' && path[1]=='\\' && path[2] && path[2]!='\\'
337 && strchr(path+3,'\\')) {
338 /* We have a UNC path: \\servername\sharename... */
339 const char *sharename, *root;
342 sharename = strchr(path+3,'\\')+1;
343 root = strchr(sharename,'\\');
345 disklen = root - path;
347 disklen = strlen(path);
349 retval = malloc(disklen + 1 + strlen(template) + 1);
350 memcpy(retval, path, disklen);
351 retval[disklen] = '\\';
352 strcpy(retval + disklen + 1, template);
353 } else if ((*path>='A' && *path<='Z' || *path>='a' && *path<='z') &&
355 retval = malloc(3 + strlen(template) + 1);
359 strcpy(retval + 3, template);
365 n = GetCurrentDirectoryW(0, NULL);
366 buf = malloc(n * sizeof(wchar_t));
368 if (GetCurrentDirectoryW(n, buf)) {
369 dir = razor_utf16_to_utf8(buf, n - 1);
371 retval = razor_file_mkdtemp_near(dir, template, error);
375 retval = malloc(3 + strlen(template) + 1);
379 strcpy(retval + 3, template);
386 * Find the mount point (assuming we can write to the
387 * whole filesystem). Otherwise stop at the first
388 * unwritable directory and take one step back.
390 char *s, *abspath, saved;
391 int len, can_step_back = 0;
395 abspath = absolute_path(path);
397 razor_set_error_posix(error, path);
401 if (stat(abspath, &buf) < 0) {
405 razor_set_error_posix(error, abspath);
410 filesystem = buf.st_dev;
412 len = strlen(abspath);
413 while(len > 1 && (s = strrchr(abspath, '/'))) {
417 len = s + 1 - abspath;
423 if (stat(abspath, &buf) < 0) {
427 razor_set_error_posix(error, abspath);
431 } else if (!filesystem)
432 filesystem = buf.st_dev;
434 if (buf.st_dev != filesystem || access(abspath, W_OK)) {
441 len = strlen(abspath);
448 len = 0; /* Avoid an unslightly double slash. */
449 retval = malloc(len + 1 + strlen(template) + 1);
450 memcpy(retval, abspath, len);
452 strcpy(retval + len + 1, template);
457 if (!mkdtemp(retval)) {
462 char *s = strdup(template);
465 if (stat(".", &buf) < 0) {
466 razor_set_error_posix(error, ".");
471 if (buf.st_dev != filesystem)
473 * Don't use a different filesystem. It will
474 * only fail later on (in rename) and cause
475 * an unhelpful error message (EXDEV).
489 razor_set_error(error, RAZOR_POSIX_ERROR, err, retval,
510 #define OPEN_DIR_USED (1U<<0)
512 struct array open_dirs = { 0, };
514 void *razor_file_opendir(const char *path, struct razor_error **error)
516 struct open_dir *od, *odend;
518 odend = open_dirs.data + open_dirs.size;
519 for (od = open_dirs.data; od < odend; od++)
520 if (!(od->flags & OPEN_DIR_USED))
523 od = array_add(&open_dirs, sizeof *od);
528 od->path2 = razor_utf8_to_utf16(path, -1);
529 od->dp = _wopendir(od->path2);
531 od->path = strdup(path);
532 od->dp = opendir(od->path);
537 razor_set_error_mswin(error, od->path2, GetLastError());
540 razor_set_error_posix(error, od->path);
546 od->flags = OPEN_DIR_USED;
550 char *razor_file_readdir(void *dp, struct razor_error **error)
552 struct open_dir *od = dp, *odend;
554 struct _wdirent *dirp;
560 odend = open_dirs.data + open_dirs.size;
561 if (dp < open_dirs.data || od >= odend || !(od->flags & OPEN_DIR_USED))
567 while((dirp = _wreaddir(od->dp))) {
568 path = razor_utf16_to_utf8(dirp->d_name, -1);
569 if (strcmp(path, ".") && strcmp(path, ".."))
575 while((dirp = readdir(od->dp)))
576 if (strcmp(dirp->d_name, ".") && strcmp(dirp->d_name, ".."))
577 return strdup(dirp->d_name);
582 razor_set_error_mswin(error, od->path2, GetLastError());
584 razor_set_error_posix(error, od->path);
591 int razor_file_closedir(void *dp, struct razor_error **error)
593 struct open_dir *od = dp, *odend;
596 odend = open_dirs.data + open_dirs.size;
597 if (dp < open_dirs.data || od >= odend || !(od->flags & OPEN_DIR_USED))
602 * I can't find documentation to state that _wclosedir()
603 * returns -1 on failure, so be paranoid.
605 retval = _wclosedir(od->dp) ? -1 : 0;
607 retval = closedir(od->dp);
612 razor_set_error_mswin(error, od->path2, GetLastError());
614 razor_set_error_posix(error, od->path);
624 od->flags &= ~OPEN_DIR_USED;
626 for (od = open_dirs.data; od < odend; od++)
627 if (od->flags & OPEN_DIR_USED)
631 array_release(&open_dirs);
632 array_init(&open_dirs);
638 struct razor_uri_vtable_entry {
639 struct razor_uri_vtable vtable;
641 struct array open_files, open_directories;
644 static struct array razor_uri_vtable_entries;
646 static struct razor_uri_vtable_entry *
647 razor_uri_get_vtable_entry(const char *scheme)
649 struct razor_uri_vtable_entry *entry, *eend, *fallback = NULL;
651 eend = razor_uri_vtable_entries.data + razor_uri_vtable_entries.size;
652 for(entry = razor_uri_vtable_entries.data; entry < eend; entry++) {
653 if (!strcmp0(entry->scheme, scheme))
655 else if (!entry->scheme)
662 int razor_uri_mkdir(const char *uri, mode_t mode, struct razor_error **error)
667 struct razor_uri_vtable_entry *entry;
668 struct razor_error *tmp_error = NULL;
670 if (razor_uri_parse(&ru, uri, error))
673 path = razor_path_from_parsed_uri(&ru, &tmp_error);
675 if (razor_error_matches(tmp_error, RAZOR_GENERAL_ERROR,
676 RAZOR_GENERAL_ERROR_UNSUPPORTED_URI))
677 razor_error_free(tmp_error);
679 razor_propagate_error(error, tmp_error, NULL);
680 razor_uri_destroy(&ru);
685 razor_uri_destroy(&ru);
686 retval = razor_file_mkdir(path, mode, error);
689 entry = razor_uri_get_vtable_entry(ru.scheme);
690 razor_uri_destroy(&ru);
691 if (!entry || !entry->vtable.mkdir) {
693 razor_set_error(error, RAZOR_GENERAL_ERROR,
694 RAZOR_GENERAL_ERROR_UNSUPPORTED_URI,
695 uri, "No URI handler installed");
697 retval = entry->vtable.mkdir(uri, mode, error);
703 int razor_uri_unlink(const char *uri, struct razor_error **error)
708 struct razor_uri_vtable_entry *entry;
709 struct razor_error *tmp_error = NULL;
711 if (razor_uri_parse(&ru, uri, error))
714 path = razor_path_from_parsed_uri(&ru, &tmp_error);
716 if (razor_error_matches(tmp_error, RAZOR_GENERAL_ERROR,
717 RAZOR_GENERAL_ERROR_UNSUPPORTED_URI))
718 razor_error_free(tmp_error);
720 razor_propagate_error(error, tmp_error, NULL);
721 razor_uri_destroy(&ru);
726 razor_uri_destroy(&ru);
727 retval = razor_file_unlink(path, error);
730 entry = razor_uri_get_vtable_entry(ru.scheme);
731 razor_uri_destroy(&ru);
732 if (!entry || !entry->vtable.unlink) {
734 razor_set_error(error, RAZOR_GENERAL_ERROR,
735 RAZOR_GENERAL_ERROR_UNSUPPORTED_URI,
736 uri, "No URI handler installed");
738 retval = entry->vtable.unlink(uri, error);
744 int razor_uri_open(const char *uri, int flags, mode_t mode,
745 struct razor_error **error)
750 struct razor_uri_vtable_entry *entry;
751 struct razor_error *tmp_error = NULL;
753 if (razor_uri_parse(&ru, uri, error))
756 path = razor_path_from_parsed_uri(&ru, &tmp_error);
758 if (razor_error_matches(tmp_error, RAZOR_GENERAL_ERROR,
759 RAZOR_GENERAL_ERROR_UNSUPPORTED_URI))
760 razor_error_free(tmp_error);
762 razor_propagate_error(error, tmp_error, NULL);
763 razor_uri_destroy(&ru);
768 razor_uri_destroy(&ru);
769 retval = razor_file_open(path, flags, mode, error);
772 entry = razor_uri_get_vtable_entry(ru.scheme);
773 razor_uri_destroy(&ru);
774 if (!entry || !entry->vtable.open) {
776 razor_set_error(error, RAZOR_GENERAL_ERROR,
777 RAZOR_GENERAL_ERROR_UNSUPPORTED_URI,
778 uri, "No URI handler installed");
780 retval = entry->vtable.open(uri, flags, mode, error);
786 int razor_uri_move(const char *src_uri, const char *dst_uri,
787 struct razor_error **error)
790 char *src_path, *dst_path;
791 struct razor_uri src_ru, dst_ru;
792 struct razor_uri_vtable_entry *entry;
793 struct razor_error *tmp_error = NULL;
795 if (razor_uri_parse(&src_ru, src_uri, error) ||
796 razor_uri_parse(&dst_ru, dst_uri, error))
799 src_path = razor_path_from_parsed_uri(&src_ru, &tmp_error);
801 if (razor_error_matches(tmp_error, RAZOR_GENERAL_ERROR,
802 RAZOR_GENERAL_ERROR_UNSUPPORTED_URI))
803 razor_error_free(tmp_error);
804 else if (!src_path) {
805 razor_propagate_error(error, tmp_error, NULL);
806 razor_uri_destroy(&src_ru);
810 dst_path = razor_path_from_parsed_uri(&dst_ru, &tmp_error);
812 if (razor_error_matches(tmp_error, RAZOR_GENERAL_ERROR,
813 RAZOR_GENERAL_ERROR_UNSUPPORTED_URI))
814 razor_error_free(tmp_error);
815 else if (!dst_path) {
816 razor_propagate_error(error, tmp_error, NULL);
817 razor_uri_destroy(&dst_ru);
818 razor_uri_destroy(&src_ru);
823 if (src_path && dst_path)
824 retval = razor_file_move(src_path, dst_path, error);
826 if (!strcmp(src_ru.scheme, dst_ru.scheme))
827 entry = razor_uri_get_vtable_entry(src_ru.scheme);
830 if (entry && entry->vtable.move)
831 retval = entry->vtable.move(src_uri, dst_uri, error);
832 else if (strcmp(src_ru.scheme, dst_ru.scheme)) {
834 razor_set_error(error, RAZOR_GENERAL_ERROR,
835 RAZOR_GENERAL_ERROR_UNSUPPORTED_URI,
836 dst_uri, "Cross-scheme URI move");
839 razor_set_error(error, RAZOR_GENERAL_ERROR,
840 RAZOR_GENERAL_ERROR_UNSUPPORTED_URI,
841 src_path ? dst_uri : src_uri,
842 "No URI handler installed");
846 razor_uri_destroy(&src_ru);
847 razor_uri_destroy(&dst_ru);
854 void *razor_uri_get_contents(const char *uri, size_t *length, int private,
855 struct razor_error **error)
860 struct razor_uri_vtable_entry *entry;
861 struct razor_error *tmp_error = NULL;
863 if (razor_uri_parse(&ru, uri, error))
866 path = razor_path_from_parsed_uri(&ru, &tmp_error);
868 if (razor_error_matches(tmp_error, RAZOR_GENERAL_ERROR,
869 RAZOR_GENERAL_ERROR_UNSUPPORTED_URI))
870 razor_error_free(tmp_error);
872 razor_propagate_error(error, tmp_error, NULL);
873 razor_uri_destroy(&ru);
878 razor_uri_destroy(&ru);
879 retval = razor_file_get_contents(path, length, private, error);
882 entry = razor_uri_get_vtable_entry(ru.scheme);
883 razor_uri_destroy(&ru);
884 if (!entry || !entry->vtable.get_contents) {
886 razor_set_error(error, RAZOR_GENERAL_ERROR,
887 RAZOR_GENERAL_ERROR_UNSUPPORTED_URI,
888 uri, "No URI handler installed");
890 retval = entry->vtable.get_contents(uri, length,
893 ptr_array_add(&entry->open_files, retval);
900 int razor_uri_free_contents(void *addr, size_t length)
903 struct razor_uri_vtable_entry *entry, *eend;
908 retval = razor_file_free_contents(addr, length);
913 eend = razor_uri_vtable_entries.data + razor_uri_vtable_entries.size;
914 for (entry = razor_uri_vtable_entries.data; entry < eend; entry++) {
915 of = ptr_array_find(&entry->open_files, addr);
917 if (entry->vtable.free_contents)
918 retval = entry->vtable.free_contents(addr,
920 ptr_array_remove_index(&entry->open_files, of);
928 int razor_uri_is_directory(const char *uri, struct razor_error **error)
933 struct razor_uri_vtable_entry *entry;
934 struct razor_error *tmp_error = NULL;
936 if (razor_uri_parse(&ru, uri, error))
939 path = razor_path_from_parsed_uri(&ru, &tmp_error);
941 if (razor_error_matches(tmp_error, RAZOR_GENERAL_ERROR,
942 RAZOR_GENERAL_ERROR_UNSUPPORTED_URI))
943 razor_error_free(tmp_error);
945 razor_propagate_error(error, tmp_error, NULL);
946 razor_uri_destroy(&ru);
951 razor_uri_destroy(&ru);
952 retval = razor_file_is_directory(path, error);
955 entry = razor_uri_get_vtable_entry(ru.scheme);
956 razor_uri_destroy(&ru);
957 if (!entry || !entry->vtable.is_directory) {
959 razor_set_error(error, RAZOR_GENERAL_ERROR,
960 RAZOR_GENERAL_ERROR_UNSUPPORTED_URI,
961 uri, "No URI handler installed");
963 retval = entry->vtable.is_directory(uri, error);
969 char *razor_uri_mkdtemp_near(const char *uri, const char *template,
970 struct razor_error **error)
975 struct razor_uri_vtable_entry *entry;
976 struct razor_error *tmp_error = NULL;
978 if (razor_uri_parse(&ru, uri, error))
981 path = razor_path_from_parsed_uri(&ru, &tmp_error);
983 if (razor_error_matches(tmp_error, RAZOR_GENERAL_ERROR,
984 RAZOR_GENERAL_ERROR_UNSUPPORTED_URI))
985 razor_error_free(tmp_error);
987 razor_propagate_error(error, tmp_error, NULL);
988 razor_uri_destroy(&ru);
993 razor_uri_destroy(&ru);
994 s = razor_file_mkdtemp_near(path, template, error);
995 retval = razor_path_to_uri(s);
999 entry = razor_uri_get_vtable_entry(ru.scheme);
1000 razor_uri_destroy(&ru);
1001 if (!entry || !entry->vtable.mkdtemp_near) {
1003 razor_set_error(error, RAZOR_GENERAL_ERROR,
1004 RAZOR_GENERAL_ERROR_UNSUPPORTED_URI,
1005 uri, "No URI handler installed");
1007 retval = entry->vtable.mkdtemp_near(uri, template,
1014 void *razor_uri_opendir(const char *uri, struct razor_error **error)
1018 struct razor_uri ru;
1019 struct razor_uri_vtable_entry *entry;
1020 struct razor_error *tmp_error = NULL;
1022 if (razor_uri_parse(&ru, uri, error))
1025 path = razor_path_from_parsed_uri(&ru, &tmp_error);
1027 if (razor_error_matches(tmp_error, RAZOR_GENERAL_ERROR,
1028 RAZOR_GENERAL_ERROR_UNSUPPORTED_URI))
1029 razor_error_free(tmp_error);
1031 razor_propagate_error(error, tmp_error, NULL);
1032 razor_uri_destroy(&ru);
1037 razor_uri_destroy(&ru);
1038 retval = razor_file_opendir(path, error);
1041 entry = razor_uri_get_vtable_entry(ru.scheme);
1042 razor_uri_destroy(&ru);
1043 if (!entry || !entry->vtable.opendir) {
1045 razor_set_error(error, RAZOR_GENERAL_ERROR,
1046 RAZOR_GENERAL_ERROR_UNSUPPORTED_URI,
1047 uri, "No URI handler installed");
1049 retval = entry->vtable.opendir(uri, error);
1051 ptr_array_add(&entry->open_directories, retval);
1058 char *razor_uri_readdir(void *dir, struct razor_error **error)
1062 struct razor_uri_vtable_entry *entry, *eend;
1064 retval = razor_file_readdir(dir, error);
1066 if (retval != (char *)-1)
1069 eend = razor_uri_vtable_entries.data + razor_uri_vtable_entries.size;
1070 for (entry = razor_uri_vtable_entries.data; entry < eend; entry++) {
1071 od = ptr_array_find(&entry->open_directories, dir);
1073 if (entry->vtable.readdir)
1074 retval = entry->vtable.readdir(dir, error);
1079 if (retval == (char *)-1) {
1081 razor_set_error(error, RAZOR_GENERAL_ERROR,
1082 RAZOR_GENERAL_ERROR_FAILED, NULL,
1083 "Invalid directory handle");
1089 int razor_uri_closedir(void *dir, struct razor_error **error)
1093 struct razor_uri_vtable_entry *entry, *eend;
1095 retval = razor_file_closedir(dir, error);
1100 eend = razor_uri_vtable_entries.data + razor_uri_vtable_entries.size;
1101 for (entry = razor_uri_vtable_entries.data; entry < eend; entry++) {
1102 od = ptr_array_find(&entry->open_directories, dir);
1104 if (entry->vtable.closedir)
1105 retval = entry->vtable.closedir(dir, error);
1111 razor_set_error(error, RAZOR_GENERAL_ERROR,
1112 RAZOR_GENERAL_ERROR_FAILED, NULL,
1113 "Invalid directory handle");
1118 RAZOR_EXPORT int razor_uri_set_vtable(const char *scheme,
1119 struct razor_uri_vtable *vtable, struct razor_error **error)
1121 struct razor_uri_vtable_entry *entry, *eend;
1123 if (!strcmp0(scheme, "file")) {
1125 * There's no fundamental reason why we couldn't support
1126 * this, but it's a lot of work without any obvious need.
1128 razor_set_error(error, RAZOR_GENERAL_ERROR,
1129 RAZOR_GENERAL_ERROR_FAILED, scheme,
1130 "Can't override file scheme handler");
1134 if (vtable->structure_size < sizeof(struct razor_uri_vtable)) {
1136 * A future version of the API might add vfuncs to the
1137 * table (which we ignore), but won't remove any.
1139 razor_set_error(error, RAZOR_GENERAL_ERROR,
1140 RAZOR_GENERAL_ERROR_FAILED, scheme,
1141 "Invalid vtable structure size");
1145 eend = razor_uri_vtable_entries.data + razor_uri_vtable_entries.size;
1146 for (entry = razor_uri_vtable_entries.data; entry < eend; entry++) {
1147 if (!strcmp0(entry->scheme, scheme))
1151 if (entry == eend) {
1154 entry = array_add(&razor_uri_vtable_entries, sizeof *entry);
1155 entry->scheme = scheme ? strdup(scheme) : NULL;
1156 array_init(&entry->open_files);
1157 array_init(&entry->open_directories);
1158 } else if (entry->open_files.size || entry->open_directories.size) {
1159 razor_set_error(error, RAZOR_GENERAL_ERROR,
1160 RAZOR_GENERAL_ERROR_FAILED, scheme,
1161 "URI handler busy");
1166 entry->vtable = *vtable;
1167 entry->vtable.structure_size = sizeof(struct razor_uri_vtable);
1169 free(entry->scheme);
1170 if (entry + 1 < eend)
1171 memmove(entry, entry + 1, eend - (entry + 1));
1172 array_set_size(&razor_uri_vtable_entries,
1173 razor_uri_vtable_entries.size - sizeof *entry);