blob: 6988821ce95983d6ce440fba06549306e144a7bf [file] [log] [blame]
/*
* Copyright (C) Tildeslash Ltd. All rights reserved.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License version 3.
*
* This program 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* In addition, as a special exception, the copyright holders give
* permission to link the code of portions of this program with the
* OpenSSL library under certain conditions as described in each
* individual source file, and distribute linked combinations
* including the two.
*
* You must obey the GNU Affero General Public License in all respects
* for all of the code used other than OpenSSL.
*/
#include "Config.h"
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <time.h>
#include <ctype.h>
#include "Str.h"
#include "system/System.h"
#include "File.h"
/**
* Implementation of the File Facade for Unix systems.
*
* @see http://www.mmonit.com/
* @file
*/
/* ----------------------------------------------------------- Definitions */
#define DEFAULT_PERM 0666
#define RETURN_FILETYPE(X) do { \
switch ((X) & S_IFMT) { \
case S_IFREG: return 'r'; \
case S_IFDIR: return 'd'; \
case S_IFCHR: return 'c'; \
case S_IFBLK: return 'b'; \
case S_IFLNK: return 'l'; \
case S_IFIFO: return 'p'; \
case S_IFSOCK: return 's'; \
default: return '?'; \
} } while (0)
const char SEPARATOR_CHAR = '/';
const char *SEPARATOR = "/";
const char PATH_SEPARATOR_CHAR = ':';
const char *PATH_SEPARATOR = ":";
/* ---------------------------------------------------------------- Public */
int File_open(const char *file, const char *mode) {
if (file && mode) {
switch(mode[0]) {
case 'r':
switch (mode[1]) {
case '+': return open(file, O_RDWR|O_NONBLOCK);
default: return open(file, O_RDONLY|O_NONBLOCK);
}
case 'w':
switch (mode[1]) {
case '+': return open(file, O_CREAT|O_RDWR|O_TRUNC|O_NONBLOCK, DEFAULT_PERM);
default: return open(file, O_CREAT|O_WRONLY|O_TRUNC|O_NONBLOCK, DEFAULT_PERM);
}
case 'a':
switch (mode[1]) {
case '+': return open(file, O_CREAT|O_RDWR|O_APPEND|O_NONBLOCK, DEFAULT_PERM);
default: return open(file, O_CREAT|O_WRONLY|O_APPEND|O_NONBLOCK, DEFAULT_PERM);
}
}
}
errno = EINVAL;
return -1;
}
int File_close(int fd) {
int r;
do
r = close(fd);
while (r == -1 && errno == EINTR);
return (r == 0);
}
int File_rewind(int fd) {
return (lseek(fd, 0, SEEK_SET) >=0);
}
time_t File_mtime(const char *file) {
if (file) {
struct stat buf;
if (stat(file, &buf) == 0)
return buf.st_mtime;
}
return -1;
}
time_t File_ctime(const char *file) {
if (file) {
struct stat buf;
if (stat(file, &buf) == 0)
return buf.st_ctime;
}
return -1;
}
time_t File_atime(const char *file) {
if (file) {
struct stat buf;
if (stat(file, &buf) == 0)
return buf.st_atime;
}
return -1;
}
int File_isFile(const char *file) {
if (file) {
struct stat buf;
return (stat(file, &buf) == 0 && S_ISREG(buf.st_mode));
}
return false;
}
int File_isDirectory(const char *file) {
if (file) {
struct stat buf;
return (stat(file, &buf) == 0 && S_ISDIR(buf.st_mode));
}
return false;
}
int File_exist(const char *file) {
if (file) {
struct stat buf;
return (stat(file, &buf) == 0);
}
return false;
}
char File_type(const char *file) {
if (file) {
struct stat buf;
if (stat(file, &buf) == 0)
RETURN_FILETYPE(buf.st_mode);
}
return '?';
}
off_t File_size(const char *file) {
if (file) {
struct stat buf;
if (stat(file, &buf) < 0)
return -1;
return buf.st_size;
}
return -1;
}
int File_chmod(const char *file, mode_t mode) {
if (file)
return (chmod(file, mode) == 0);
errno = EINVAL;
return false;
}
mode_t File_mod(const char *file) {
if (file) {
struct stat buf;
if (stat(file, &buf) == 0)
return buf.st_mode;
}
return -1;
}
mode_t File_umask(void) {
mode_t omask = umask(0);
umask(omask);
return omask;
}
mode_t File_setUmask(mode_t mask) {
mode_t omask = umask(mask);
return omask;
}
int File_isReadable(const char *file) {
if (file)
return (access(file, R_OK) == 0);
return false;
}
int File_isWritable(const char *file) {
if (file)
return (access(file, W_OK) == 0);
return false;
}
int File_isExecutable(const char *file) {
if (file)
return (access(file, X_OK) == 0);
return false;
}
int File_delete(const char *file) {
if (file)
return (remove(file) == 0);
errno = ENOENT;
return false;
}
int File_rename(const char *file, const char *name) {
if (file)
return (rename(file, name) == 0);
errno = ENOENT;
return false;
}
const char *File_basename(const char *path) {
if ((STR_DEF(path))) {
char *f = strrchr(path, SEPARATOR_CHAR);
return (f ? ++f : path);
}
return path;
}
char *File_dirname(char *path) {
if ((STR_DEF(path))) {
char *d = strrchr(path, SEPARATOR_CHAR);
if (d)
*(d + 1) = 0; /* Keep last separator */
else {
path[0] = '.';
path[1] = 0;
}
}
return path;
}
const char *File_extension(const char *path) {
if (STR_DEF(path)) {
char *e = strrchr(path, '.');
return (e ? ++e : NULL);
}
return NULL;
}
char *File_removeTrailingSeparator(char *path) {
if (STR_DEF(path)) {
char *p;
for (p = path; *p; p++);
do
*(p--) = 0;
while ((p > path) && (isspace(*p) || *p == SEPARATOR_CHAR));
}
return path;
}
char *File_getRealPath(const char *path, char *resolved) {
if (path && resolved)
return realpath(path, resolved);
return NULL;
}