1// LAF Base Library
2// Copyright (c) 2020-2021 Igara Studio S.A.
3// Copyright (c) 2001-2018 David Capello
4//
5// This file is released under the terms of the MIT license.
6// Read LICENSE.txt for more information.
7
8#ifdef HAVE_CONFIG_H
9#include "config.h"
10#endif
11
12#include "base/file_handle.h"
13
14#include "base/string.h"
15
16#include <stdexcept>
17
18#if LAF_WINDOWS
19 #include <windows.h>
20 #include <io.h>
21#endif
22
23#include <sys/stat.h>
24#include <fcntl.h>
25
26#ifndef O_BINARY
27#define O_BINARY 0
28#define O_TEXT 0
29#endif
30
31using namespace std;
32
33namespace base {
34
35static void fclose_if_valid(FILE* f)
36{
37 if (f)
38 fclose(f);
39}
40
41static void throw_cannot_open_exception(const string& filename, const string& mode)
42{
43 if (mode.find('w') != string::npos)
44 throw std::runtime_error("Cannot save file " + filename + " in the given location");
45 else
46 throw std::runtime_error("Cannot open file " + filename);
47}
48
49FILE* open_file_raw(const string& filename, const string& mode)
50{
51#if LAF_WINDOWS
52 return _wfopen(from_utf8(filename).c_str(),
53 from_utf8(mode).c_str());
54#else
55 return fopen(filename.c_str(), mode.c_str());
56#endif
57}
58
59FileHandle open_file(const string& filename, const string& mode)
60{
61 return FileHandle(open_file_raw(filename, mode), fclose_if_valid);
62}
63
64FileHandle open_file_with_exception(const string& filename, const string& mode)
65{
66 FileHandle f(open_file_raw(filename, mode), fclose_if_valid);
67 if (!f)
68 throw_cannot_open_exception(filename, mode);
69 return f;
70}
71
72FileHandle open_file_with_exception_sync_on_close(const std::string& filename, const std::string& mode)
73{
74 FileHandle f(open_file_raw(filename, mode), close_file_and_sync);
75 if (!f)
76 throw_cannot_open_exception(filename, mode);
77 return f;
78}
79
80int open_file_descriptor_with_exception(const string& filename, const string& mode)
81{
82 int flags = 0;
83 if (mode.find('r') != string::npos) flags |= O_RDONLY;
84 if (mode.find('w') != string::npos) flags |= O_RDWR | O_CREAT | O_TRUNC;
85 if (mode.find('b') != string::npos) flags |= O_BINARY;
86
87 int fd;
88#if LAF_WINDOWS
89 fd = _wopen(from_utf8(filename).c_str(), flags, _S_IREAD | _S_IWRITE);
90#else
91 fd = open(filename.c_str(), flags, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH);
92#endif
93
94 if (fd == -1)
95 throw_cannot_open_exception(filename, mode);
96
97 return fd;
98}
99
100void sync_file_descriptor(int fd)
101{
102#if LAF_WINDOWS
103 HANDLE handle = (HANDLE)_get_osfhandle(fd);
104 if (handle)
105 FlushFileBuffers(handle);
106#endif
107}
108
109void close_file_and_sync(FILE* file)
110{
111 if (!file)
112 return;
113
114 fflush(file);
115#if LAF_WINDOWS
116 int fd = _fileno(file);
117 if (fd)
118 sync_file_descriptor(fd);
119#endif
120 fclose(file);
121}
122
123}
124