1 /*
2  * Copyright (C) 2018 Matthieu Gautier <mgautier@kymeria.fr>
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License as
6  * published by the Free Software Foundation; either version 2 of the
7  * License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied
11  * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and
12  * NON-INFRINGEMENT.  See the GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
17  *
18  */
19 
20 #include "fs_unix.h"
21 #include <stdexcept>
22 
23 #include <sys/types.h>
24 #include <sys/stat.h>
25 #include <fcntl.h>
26 #include <unistd.h>
27 #include <dirent.h>
28 #include <errno.h>
29 
30 namespace zim
31 {
32 
33 namespace unix {
34 
readAt(char * dest,zsize_t size,offset_t offset) const35 zsize_t FD::readAt(char* dest, zsize_t size, offset_t offset) const
36 {
37 #if defined(__APPLE__) || defined(__OpenBSD__) || defined(__FreeBSD__) || \
38   defined(__DragonFly__)
39 # define PREAD pread
40 #else
41 # define PREAD pread64
42 #endif
43   ssize_t full_size_read = 0;
44   auto size_to_read = size.v;
45   auto current_offset = offset.v;
46   errno = 0;
47   while (size_to_read > 0) {
48     auto size_read = PREAD(m_fd, dest, size_to_read, current_offset);
49     if (size_read == -1) {
50       return zsize_t(-1);
51     }
52     size_to_read -= size_read;
53     current_offset += size_read;
54     full_size_read += size_read;
55   }
56   return zsize_t(full_size_read);
57 #undef PREAD
58 }
59 
getSize() const60 zsize_t FD::getSize() const
61 {
62   struct stat sb;
63   fstat(m_fd, &sb);
64   return zsize_t(sb.st_size);
65 }
66 
seek(offset_t offset)67 bool FD::seek(offset_t offset)
68 {
69     return static_cast<int64_t>(offset.v) == lseek(m_fd, offset.v, SEEK_SET);
70 }
71 
close()72 bool FD::close() {
73   if (m_fd != -1) {
74     return ::close(m_fd);
75   }
76   return -1;
77 }
78 
openFile(path_t filepath)79 FD FS::openFile(path_t filepath)
80 {
81   int fd = open(filepath.c_str(), O_RDONLY);
82   if (fd == -1) {
83     throw std::runtime_error("");
84   }
85   return FD(fd);
86 }
87 
makeDirectory(path_t path)88 bool FS::makeDirectory(path_t path)
89 {
90   return !mkdir(path.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
91 }
92 
rename(path_t old_path,path_t new_path)93 void FS::rename(path_t old_path, path_t new_path)
94 {
95   ::rename(old_path.c_str(), new_path.c_str());
96 }
97 
join(path_t base,path_t name)98 std::string FS::join(path_t base, path_t name)
99 {
100   return base + "/" + name;
101 }
102 
remove(path_t path)103 bool FS::remove(path_t path)
104 {
105   DIR* dir;
106   /* It's a directory, remove all its entries first */
107   if ((dir = opendir(path.c_str())) != NULL) {
108     struct dirent* ent;
109     while ((ent = readdir(dir)) != NULL) {
110       std::string childName = ent->d_name;
111       if (childName !=  "." && childName != "..") {
112         auto childPath = join(path, childName);
113         remove(childPath);
114       }
115     }
116     closedir(dir);
117     return removeDir(path);
118   }
119 
120   /* It's a file */
121   else {
122     return removeFile(path);
123   }
124 }
125 
removeDir(path_t path)126 bool FS::removeDir(path_t path) {
127   return rmdir(path.c_str());
128 }
129 
removeFile(path_t path)130 bool FS::removeFile(path_t path) {
131   return ::remove(path.c_str());
132 }
133 
134 
135 }; // unix namespace
136 
137 }; // zim namespace
138 
139