2020-01-04 10:28:03 +01:00
|
|
|
#include <string.h>
|
2020-01-01 12:11:34 +01:00
|
|
|
#include <assert.h>
|
|
|
|
|
|
|
|
// error_message_format
|
|
|
|
#include "utils.h"
|
|
|
|
#include "fs.h"
|
|
|
|
|
|
|
|
/**
|
|
|
|
Private functions finish with an underscore
|
|
|
|
*/
|
|
|
|
|
|
|
|
int exists_ (const char *path, struct stat *status)
|
|
|
|
{
|
|
|
|
assert (status != NULL);
|
|
|
|
return stat (path, status) == 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int is_directory_ (struct stat *status)
|
|
|
|
{
|
|
|
|
assert (status != NULL);
|
|
|
|
return S_ISDIR (status->st_mode);
|
|
|
|
}
|
|
|
|
|
|
|
|
int is_writable_ (struct stat *status)
|
|
|
|
{
|
|
|
|
assert (status != NULL);
|
|
|
|
// what is my effective uid?
|
|
|
|
uid_t uid = geteuid ();
|
|
|
|
gid_t gid = getegid ();
|
|
|
|
|
|
|
|
if (status->st_uid == uid) {
|
|
|
|
// does the user can write?
|
|
|
|
return (status->st_mode & S_IWUSR) != 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (status->st_gid == gid) {
|
|
|
|
// does the group can write?
|
|
|
|
return (status->st_mode & S_IWGRP) != 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return (status->st_mode & S_IWOTH) != 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/** avoiding name clashes */
|
|
|
|
int dirname_ (const char *path, char *dname)
|
|
|
|
{
|
|
|
|
assert (dname != NULL);
|
|
|
|
|
2020-01-04 10:28:03 +01:00
|
|
|
char *last_slash = strrchr (path, '/');
|
2020-01-01 12:11:34 +01:00
|
|
|
int pathlen = last_slash - path;
|
|
|
|
|
|
|
|
snprintf (dname, pathlen + 1, "%s", path);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct ipc_error mkdir_p_ (const char *path)
|
|
|
|
{
|
|
|
|
int dir_rights = 01750;
|
|
|
|
|
|
|
|
// notes:
|
|
|
|
// S_ISGID
|
|
|
|
// files and sub-directories are automatically in the same group of the root directory
|
|
|
|
// S_ISVTX = "sticky bit"
|
|
|
|
// files created in this dir can only be removed by the owner or the directory owner
|
|
|
|
// so in /tmp even people with writing rights cannot remove other's content
|
|
|
|
|
|
|
|
SECURE_BUFFER_DECLARATION (char, _path, BUFSIZ);
|
|
|
|
const size_t len = strlen (path);
|
|
|
|
char *p;
|
|
|
|
|
|
|
|
errno = 0;
|
|
|
|
|
|
|
|
/* copy the string so it becomes mutable */
|
|
|
|
if (len > sizeof (_path) - 1) {
|
|
|
|
errno = ENAMETOOLONG;
|
|
|
|
IPC_RETURN_ERROR (IPC_ERROR_MKDIR__NAME_TOO_LONG);
|
|
|
|
}
|
|
|
|
strcpy (_path, path);
|
|
|
|
|
|
|
|
/* loop over the string, each time we have a slash we can mkdir */
|
|
|
|
for (p = _path + 1; *p; p++) {
|
|
|
|
if (*p == '/') {
|
|
|
|
/**
|
|
|
|
truncate the path to conserve the path we want to create only
|
|
|
|
*/
|
|
|
|
*p = '\0';
|
|
|
|
|
|
|
|
if (mkdir (_path, dir_rights) != 0) {
|
|
|
|
if (errno != EEXIST)
|
|
|
|
IPC_RETURN_ERROR_FORMAT (IPC_ERROR_MKDIR__CANNOT_CREATE_DIR
|
|
|
|
, "mkdir_p_: cannot create the directory %s", _path);
|
|
|
|
}
|
|
|
|
|
|
|
|
*p = '/';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (mkdir (_path, dir_rights) != 0) {
|
|
|
|
// actually, in our code this error shouldn't be possible
|
|
|
|
// since it already has been tested
|
|
|
|
if (errno != EEXIST)
|
|
|
|
IPC_RETURN_ERROR_FORMAT (IPC_ERROR_MKDIR__CANNOT_CREATE_DIR
|
|
|
|
, "mkdir: cannot create the directory %s", _path);
|
|
|
|
}
|
|
|
|
|
|
|
|
IPC_RETURN_NO_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Paramater is the path of the file we want to create
|
|
|
|
* A trailing slash '/' is required if the full path is itself a directory we need to create.
|
|
|
|
*/
|
|
|
|
struct ipc_error directory_setup_ (const char *path)
|
|
|
|
{
|
|
|
|
T_R ((path == NULL), IPC_ERROR_DIRECTORY_SETUP__PATH_PARAM);
|
|
|
|
|
|
|
|
SECURE_BUFFER_DECLARATION (char, dir, BUFSIZ);
|
|
|
|
dirname_ (path, dir);
|
|
|
|
|
|
|
|
SECURE_DECLARATION (struct stat, status);
|
|
|
|
|
|
|
|
/** If the directory doesn't exists, yet */
|
|
|
|
if (!exists_ (dir, &status)) {
|
|
|
|
/** create the whole path */
|
|
|
|
return mkdir_p_ (dir);
|
|
|
|
}
|
|
|
|
|
|
|
|
/** The path exists, is it a directory? */
|
|
|
|
if (!is_directory_ (&status)) {
|
|
|
|
IPC_RETURN_ERROR_FORMAT (IPC_ERROR_DIR_SETUP__NOT_A_DIRECTORY
|
|
|
|
, "directory_setup_: path %s is not a directory", dir);
|
|
|
|
}
|
|
|
|
|
|
|
|
/** The path exists and it is a directory. Do we have the rights to write in it? */
|
|
|
|
if (!is_writable_ (&status)) {
|
|
|
|
IPC_RETURN_ERROR_FORMAT (IPC_ERROR_DIR_SETUP__DIRECTORY_NOT_WRITABLE
|
|
|
|
, "directory_setup_: directory %s is not writable", dir);
|
|
|
|
}
|
|
|
|
|
|
|
|
IPC_RETURN_NO_ERROR;
|
|
|
|
}
|