File: path.c

package info (click to toggle)
iwd 1.14-3%2Bdeb11u1
  • links: PTS, VCS
  • area: main
  • in suites: bullseye
  • size: 6,888 kB
  • sloc: ansic: 113,786; sh: 4,325; makefile: 601
file content (190 lines) | stat: -rw-r--r-- 4,366 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
/*
 *
 *  Embedded Linux library
 *
 *  Copyright (C) 2019  Intel Corporation. All rights reserved.
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License as published by the Free Software Foundation; either
 *  version 2.1 of the License, or (at your option) any later version.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 */

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#define _GNU_SOURCE
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>

#include "time.h"
#include "path.h"
#include "useful.h"
#include "private.h"

static const char *next_in_path(const char *path, char **ret, size_t overhead)
{
	const char *p = path;
	char *r;
	size_t toalloc = 0;

	while (p[0] != '\0' && p[0] != ':') {
		switch (*p) {
		case '\\':
			if (!*++p)
				break;
			/* Fall through */
		default:
			p++;
			toalloc += 1;
			break;
		}
	}

	r = l_new(char, toalloc + 1 + overhead);
	p = path;
	*ret = r;

	while (p[0] != '\0' && p[0] != ':') {
		switch (*p) {
		case '\\':
			if (!*++p)
				break;
			/* Fall through */
		default:
			*r++ = *p++;
			break;
		}
	}

	if (p[0] == ':')
		p++;

	return p;
}

/**
 * l_path_next:
 * @path_str: contents of $PATH-like string
 * @ret: The returned value
 *
 * Attempts to parse the next element of a $PATH-like string and returns the
 * resulting directory in a newly-allocated variable assigned to @ret.  @ret
 * must be a valid pointer to a char *.
 *
 * Returns: A pointer inside @path_str that begins just past the next ':'
 * delimiter character or to the end of the string.
 **/
LIB_EXPORT const char *l_path_next(const char *path_str, char **ret)
{
	if (unlikely(!path_str))
		return NULL;

	return next_in_path(path_str, ret, 0);
}

/**
 * l_path_find:
 * @basename: The basename of the file, e.g. "vi"
 * @path_str: A list of paths formatted like $PATH, e.g. from getenv
 * @mode: mode to check.  This is the same mode as would be fed to access()
 *
 * Attempts to find @basename in one of the directories listed in @path_str.
 * Only directories with absolute paths are used.
 *
 * Returns: A newly-allocated string with the full path of the resolved file
 * given by @basename.  E.g. /usr/bin/vi.  Or NULL if no file could be found
 * that matches the given @mode.
 */
LIB_EXPORT char *l_path_find(const char *basename,
					const char *path_str, int mode)
{
	size_t overhead;
	size_t len;
	char *path;

	if (unlikely(!path_str || !basename))
		return NULL;

	overhead = strlen(basename) + 1;

	do {
		path_str = next_in_path(path_str, &path, overhead);

		if (path[0] == '/') {
			len = strlen(path);

			if (path[len - 1] != '/')
				path[len++] = '/';

			strcpy(path + len, basename);

			if (access(path, mode) == 0)
				return path;
		}

		l_free(path);
	} while (path_str[0] != '\0');

	return NULL;
}

/**
 * l_path_get_mtime:
 * @path: The path of the file
 *
 * Attempts find the modified time of file pointed to by @path.  If @path
 * is a symbolic link, then the link is followed.
 *
 * Returns: The number of microseconds (usec) since the Epoch or L_TIME_INVALID
 * if an error occurred.
 */
LIB_EXPORT uint64_t l_path_get_mtime(const char *path)
{
	struct stat sb;
	int ret;

	if (unlikely(path == NULL))
		return L_TIME_INVALID;

	ret = stat(path, &sb);
	if (ret < 0)
		return L_TIME_INVALID;

	return (uint64_t) sb.st_mtim.tv_sec * 1000000 +
		sb.st_mtim.tv_nsec / 1000;
}

/**
 * l_path_touch:
 * @path: The path of the file
 *
 * Updates the modification and last_accessed time of the file given by @path
 * to the current time. If @path is a symbolic link, then the link is followed.
 *
 * Returns: 0 if the file times could be updated successfully and -errno
 * otherwise.
 */
LIB_EXPORT int l_path_touch(const char *path)
{
	if (unlikely(!path))
		return -EINVAL;

	if (utimensat(0, path, NULL, 0) == 0)
		return 0;

	return -errno;
}