Developer documentation
Version 3.0.3-105-gd3941f44
utils.h
Go to the documentation of this file.
1/* Copyright (c) 2008-2022 the MRtrix3 contributors.
2 *
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 *
7 * Covered Software is provided under this License on an "as is"
8 * basis, without warranty of any kind, either expressed, implied, or
9 * statutory, including, without limitation, warranties that the
10 * Covered Software is free of defects, merchantable, fit for a
11 * particular purpose or non-infringing.
12 * See the Mozilla Public License v. 2.0 for more details.
13 *
14 * For more details, see http://www.mrtrix.org/.
15 */
16
17#ifndef __file_ops_h__
18#define __file_ops_h__
19
20#include <cstdint>
21#include <sys/types.h>
22#include <sys/stat.h>
23#include <fcntl.h>
24
25#include "debug.h"
26#include "app.h"
27#include "mrtrix.h"
28#include "types.h"
29#include "file/path.h"
30#include "file/config.h"
31
32
33namespace MR
34{
35 namespace File
36 {
37
38 namespace
39 {
40 inline char random_char ()
41 {
42 char c = rand () % 62;
43 if (c < 10) return c+48;
44 if (c < 36) return c+55;
45 return c+61;
46 }
47
48 //CONF option: TmpFileDir
49 //CONF default: `/tmp` (on Unix), `.` (on Windows)
50 //CONF The prefix for temporary files (as used in pipelines). By default,
51 //CONF these files get written to the current folder on Windows machines,
52 //CONF which may cause performance issues, particularly when operating
53 //CONF over distributed file systems. On Unix machines, the default is
54 //CONF /tmp/, which is typically a RAM file system and should therefore
55 //CONF be fast; but may cause issues on machines with little RAM
56 //CONF capacity or where write-access to this location is not permitted.
57 //CONF
58 //CONF Note that this location can also be manipulated using the
59 //CONF :envvar:`MRTRIX_TMPFILE_DIR` environment variable, without editing the
60 //CONF config file. Note also that this setting does not influence the
61 //CONF location in which Python scripts construct their scratch
62 //CONF directories; that is determined based on config file option
63 //CONF ScriptScratchDir.
64
65 //ENVVAR name: MRTRIX_TMPFILE_DIR
66 //ENVVAR This has the same effect as the :option:`TmpFileDir`
67 //ENVVAR configuration file entry, and can be used to set the location of
68 //ENVVAR temporary files (as used in Unix pipes) for a single session,
69 //ENVVAR within a single script, or for a single command without
70 //ENVVAR modifying the configuration file.
71 const std::string __get_tmpfile_dir () {
72 const char* from_env_mrtrix = getenv ("MRTRIX_TMPFILE_DIR");
73 if (from_env_mrtrix)
74 return from_env_mrtrix;
75
76 const char* default_tmpdir =
77#ifdef MRTRIX_WINDOWS
78 "."
79#else
80 "/tmp"
81#endif
82 ;
83
84 const char* from_env_general = getenv ("TMPDIR");
85 if (from_env_general)
86 default_tmpdir = from_env_general;
87
88 return File::Config::get ("TmpFileDir", default_tmpdir);
89 }
90
91 const std::string& tmpfile_dir () {
92 static const std::string __tmpfile_dir = __get_tmpfile_dir();
93 return __tmpfile_dir;
94 }
95
96 //CONF option: TmpFilePrefix
97 //CONF default: `mrtrix-tmp-`
98 //CONF The prefix to use for the basename of temporary files. This will
99 //CONF be used to generate a unique filename for the temporary file, by
100 //CONF adding random characters to this prefix, followed by a suitable
101 //CONF suffix (depending on file type). Note that this prefix can also be
102 //CONF manipulated using the `MRTRIX_TMPFILE_PREFIX` environment
103 //CONF variable, without editing the config file.
104
105 //ENVVAR name: MRTRIX_TMPFILE_PREFIX
106 //ENVVAR This has the same effect as the :option:`TmpFilePrefix`
107 //ENVVAR configuration file entry, and can be used to set the prefix for
108 //ENVVAR the name of temporary files (as used in Unix pipes) for a
109 //ENVVAR single session, within a single script, or for a single command
110 //ENVVAR without modifying the configuration file.
111 const std::string __get_tmpfile_prefix () {
112 const char* from_env = getenv ("MRTRIX_TMPFILE_PREFIX");
113 if (from_env) return from_env;
114 return File::Config::get ("TmpFilePrefix", "mrtrix-tmp-");
115 }
116
117 const std::string& tmpfile_prefix () {
118 static const std::string __tmpfile_prefix = __get_tmpfile_prefix();
119 return __tmpfile_prefix;
120 }
121
122
123 /* Config file options listed here so that they can be scraped by
124 * generate_user_docs.sh and added to the list of config file options in
125 * the documentation without modifying the script to read from the scripts
126 * directory.
127 */
128
129 //CONF option: ScriptScratchDir
130 //CONF default: `.`
131 //CONF The location in which to generate the scratch directories to be
132 //CONF used by MRtrix Python scripts. By default they will be generated
133 //CONF in the working directory.
134 //CONF Note that this setting does not influence the location in which
135 //CONF piped images and other temporary files are created by MRtrix3;
136 //CONF that is determined based on config file option :option:`TmpFileDir`.
137
138 //CONF option: ScriptScratchPrefix
139 //CONF default: `<script>-tmp-`
140 //CONF The prefix to use when generating a unique name for a Python
141 //CONF script scratch directory. By default the name of the invoked
142 //CONF script itself will be used, followed by `-tmp-` (six random
143 //CONF characters are then appended to produce a unique name in cases
144 //CONF where a script may be run multiple times in parallel).
145
146 }
147
148
149
150 inline void remove (const std::string& file)
151 {
152 if (std::remove (file.c_str()))
153 throw Exception ("error deleting file \"" + file + "\": " + strerror (errno));;
154 }
155
156
157 inline void create (const std::string& filename, int64_t size = 0)
158 {
159 DEBUG (std::string("creating ") + (size ? "" : "empty ") + "file \"" + filename + "\"" + (size ? " with size " + str (size) : ""));
160
161 int fid;
162 while ( (fid = open (filename.c_str(), O_CREAT | O_RDWR | O_EXCL, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH)) < 0) {
163 if (errno == EEXIST) {
164 App::check_overwrite (filename);
165 INFO ("file \"" + filename + "\" already exists - removing");
166 remove (filename);
167 }
168 else
169 throw Exception ("error creating output file \"" + filename + "\": " + std::strerror (errno));
170 }
171 if (fid < 0) {
172 std::string mesg ("error creating file \"" + filename + "\": " + strerror (errno));
173 if (errno == EEXIST)
174 mesg += " (use -force option to force overwrite)";
175 throw Exception (mesg);
176 }
177
178 if (size) size = ftruncate (fid, size);
179 close (fid);
180
181 if (size)
182 throw Exception ("cannot resize file \"" + filename + "\": " + strerror (errno));
183 }
184
185
186
187 inline void resize (const std::string& filename, int64_t size)
188 {
189 DEBUG ("resizing file \"" + filename + "\" to " + str (size));
190
191 int fd = open (filename.c_str(), O_RDWR, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
192 if (fd < 0)
193 throw Exception ("error opening file \"" + filename + "\" for resizing: " + strerror (errno));
194 int status = ftruncate (fd, size);
195 close (fd);
196 if (status)
197 throw Exception ("cannot resize file \"" + filename + "\": " + strerror (errno));
198 }
199
200
201
202
203 inline bool is_tempfile (const std::string& name, const char* suffix = NULL)
204 {
205 if (Path::basename (name).compare (0, tmpfile_prefix().size(), tmpfile_prefix()))
206 return false;
207 if (suffix)
208 if (!Path::has_suffix (name, suffix))
209 return false;
210 return true;
211 }
212
213
214
215
216 inline std::string create_tempfile (int64_t size = 0, const char* suffix = NULL)
217 {
218 DEBUG ("creating temporary file of size " + str (size));
219
220 std::string filename (Path::join (tmpfile_dir(), tmpfile_prefix()) + "XXXXXX.");
221 int rand_index = filename.size() - 7;
222 if (suffix) filename += suffix;
223
224 int fid;
225 do {
226 for (int n = 0; n < 6; n++)
227 filename[rand_index+n] = random_char();
228 fid = open (filename.c_str(), O_CREAT | O_RDWR | O_EXCL, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
229 } while (fid < 0 && errno == EEXIST);
230
231 if (fid < 0)
232 throw Exception (std::string ("error creating temporary file in directory \"" + tmpfile_dir() + "\": ") + strerror (errno));
233
234 int status = size ? ftruncate (fid, size) : 0;
235 close (fid);
236 if (status) throw Exception ("cannot resize file \"" + filename + "\": " + strerror (errno));
237
238 return filename;
239 }
240
241
242 inline void mkdir (const std::string& folder)
243 {
244 if (::mkdir (folder.c_str()
245#ifndef MRTRIX_WINDOWS
246 , 0777
247#endif
248 ))
249 throw Exception ("error creating folder \"" + folder + "\": " + strerror (errno));
250 }
251
252 inline void rmdir (const std::string& folder, bool recursive = false)
253 {
254 if (recursive) {
255 Path::Dir dir (folder);
256 std::string entry;
257 while ((entry = dir.read_name()).size()) {
258 std::string path = Path::join (folder, entry);
259 if (Path::is_dir (path))
260 rmdir (path, true);
261 else
262 remove (path);
263 }
264 }
265 DEBUG ("deleting folder \"" + folder + "\"...");
266 if (::rmdir (folder.c_str()))
267 throw Exception ("error deleting folder \"" + folder + "\": " + strerror (errno));
268 }
269
270
271
272 }
273}
274
275#endif
276
static std::string get(const std::string &key)
Definition: config.h:36
std::string read_name()
Definition: path.h:190
#define INFO(msg)
Definition: exception.h:74
#define DEBUG(msg)
Definition: exception.h:75
void check_overwrite(const std::string &name)
Definition: app.h:168
void create(const std::string &filename, int64_t size=0)
Definition: utils.h:157
bool is_tempfile(const std::string &name, const char *suffix=NULL)
Definition: utils.h:203
void resize(const std::string &filename, int64_t size)
Definition: utils.h:187
void mkdir(const std::string &folder)
Definition: utils.h:242
void remove(const std::string &file)
Definition: utils.h:150
void rmdir(const std::string &folder, bool recursive=false)
Definition: utils.h:252
std::string create_tempfile(int64_t size=0, const char *suffix=NULL)
Definition: utils.h:216
std::string join(const std::string &first, const std::string &second)
Definition: path.h:74
std::string basename(const std::string &name)
Definition: path.h:60
bool is_dir(const std::string &path)
Definition: path.h:104
bool has_suffix(const std::string &name, const std::string &suffix)
Definition: path.h:130
Definition: base.h:24
std::string str(const T &value, int precision=0)
Definition: mrtrix.h:247
const std::string name
Definition: thread.h:108