dpkg (1.18.25) stretch; urgency=medium
[dpkg] / lib / dpkg / path.c
CommitLineData
1479465f
GJ
1/*
2 * libdpkg - Debian packaging suite library routines
3 * path.c - path handling functions
4 *
5 * Copyright © 1995 Ian Jackson <ijackson@chiark.greenend.org.uk>
6 * Copyright © 2008-2012 Guillem Jover <guillem@debian.org>
7 *
8 * This is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program. If not, see <https://www.gnu.org/licenses/>.
20 */
21
22#include <config.h>
23#include <compat.h>
24
25#include <stdlib.h>
26#include <string.h>
27#include <stdio.h>
28
29#include <dpkg/dpkg.h>
30#include <dpkg/string.h>
31#include <dpkg/path.h>
32
33/**
34 * Trim ‘/’ and ‘/.’ from the end of a pathname.
35 *
36 * The given string will get NUL-terminatd.
37 *
38 * @param path The pathname to trim.
39 *
40 * @return The size of the trimmed pathname.
41 */
42size_t
43path_trim_slash_slashdot(char *path)
44{
45 char *end;
46
47 if (str_is_unset(path))
48 return 0;
49
50 for (end = path + strlen(path) - 1; end - path >= 1; end--) {
51 if (*end == '/' || (*(end - 1) == '/' && *end == '.'))
52 *end = '\0';
53 else
54 break;
55 }
56
57 return end - path + 1;
58}
59
60/**
61 * Skip ‘/’ and ‘./’ from the beginning of a pathname.
62 *
63 * @param path The pathname to skip.
64 *
65 * @return The new beginning of the pathname.
66 */
67const char *
68path_skip_slash_dotslash(const char *path)
69{
70 while (path[0] == '/' || (path[0] == '.' && path[1] == '/'))
71 path++;
72
73 return path;
74}
75
76/**
77 * Return the last component of a pathname.
78 *
79 * @param path The pathname to get the base name from.
80 *
81 * @return A pointer to the last component inside pathname.
82 */
83const char *
84path_basename(const char *path)
85{
86 const char *last_slash;
87
88 last_slash = strrchr(path, '/');
89 if (last_slash == NULL)
90 return path;
91 else
92 return last_slash + 1;
93}
94
95/**
96 * Create a template for a temporary pathname.
97 *
98 * @param suffix The suffix to use for the template string.
99 *
100 * @return An allocated string with the created template.
101 */
102char *
103path_make_temp_template(const char *suffix)
104{
105 const char *tmpdir;
106
107 tmpdir = getenv("TMPDIR");
108 if (!tmpdir)
109 tmpdir = P_tmpdir;
110
111 return str_fmt("%s/%s.XXXXXX", tmpdir, suffix);
112}
113
114/**
115 * Escape characters in a pathname for safe locale printing.
116 *
117 * We need to quote paths so that they do not cause problems when printing
118 * them, for example with snprintf(3) which does not work if the format
119 * string contains %s and an argument has invalid characters for the
120 * current locale, it will then return -1.
121 *
122 * To simplify things, we just escape all 8 bit characters, instead of
123 * just invalid characters.
124 *
125 * @param dst The escaped destination string.
126 * @param src The source string to escape.
127 * @param n The size of the destination buffer.
128 *
129 * @return The destination string.
130 */
131char *
132path_quote_filename(char *dst, const char *src, size_t n)
133{
134 char *r = dst;
135 ssize_t size = (ssize_t)n;
136
137 if (size == 0)
138 return r;
139
140 while (*src) {
141 if (*src == '\\') {
142 size -= 2;
143 if (size <= 0)
144 break;
145
146 *dst++ = '\\';
147 *dst++ = '\\';
148 src++;
149 } else if (((*src) & 0x80) == '\0') {
150 size--;
151 if (size <= 0)
152 break;
153
154 *dst++ = *src++;
155 } else {
156 size -= 4;
157 if (size <= 0)
158 break;
159
160 sprintf(dst, "\\%03o",
161 *(const unsigned char *)src);
162 dst += 4;
163 src++;
164 }
165 }
166
167 *dst = '\0';
168
169 return r;
170}