fix confusing error message from 'got commit' upon uncommitable paths
[got-portable.git] / lib / reference_parse.c
blob4e7304f8d4535cb142c07c27aa74f1bac2ba2d40
1 /*
2 * Copyright (c) 2018, 2019 Stefan Sperling <stsp@openbsd.org>
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 #include <sys/types.h>
18 #include <sys/queue.h>
20 #include <ctype.h>
21 #include <string.h>
23 #include "got_reference.h"
25 #include "got_lib_lockfile.h"
27 #ifndef nitems
28 #define nitems(_a) (sizeof(_a) / sizeof((_a)[0]))
29 #endif
31 int
32 got_ref_name_is_valid(const char *name)
34 const char *s, *seg;
35 const char forbidden[] = { ' ', '~', '^', ':', '?', '*', '[' , '\\' };
36 const char *forbidden_seq[] = { "//", "..", "@{" };
37 const char *lfs = GOT_LOCKFILE_SUFFIX;
38 const size_t lfs_len = sizeof(GOT_LOCKFILE_SUFFIX) - 1;
39 size_t i;
41 if (name[0] == '@' && name[1] == '\0')
42 return 0;
44 s = name;
45 seg = s;
46 if (seg[0] == '\0' || seg[0] == '.' || seg[0] == '/')
47 return 0;
48 while (*s) {
49 for (i = 0; i < nitems(forbidden); i++) {
50 if (*s == forbidden[i])
51 return 0;
53 for (i = 0; i < nitems(forbidden_seq); i++) {
54 if (s[0] == forbidden_seq[i][0] &&
55 s[1] == forbidden_seq[i][1])
56 return 0;
58 if (iscntrl((unsigned char)s[0]))
59 return 0;
60 if (s[0] == '.' && s[1] == '\0')
61 return 0;
62 if (*s == '/') {
63 const char *nextseg = s + 1;
64 if (nextseg[0] == '\0' || nextseg[0] == '.' ||
65 nextseg[0] == '/')
66 return 0;
67 if (seg <= s - lfs_len &&
68 strncmp(s - lfs_len, lfs, lfs_len) == 0)
69 return 0;
70 seg = nextseg;
72 s++;
75 if (seg <= s - lfs_len &&
76 strncmp(s - lfs_len, lfs, lfs_len) == 0)
77 return 0;
79 return 1;