blob: cddb9f972f974f8e8bf4e46bd0294e4b58e6c43f [file] [log] [blame]
/*
*
* 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;
}