| /* |
| * 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; |
| } |