KiCad PCB EDA Suite
Loading...
Searching...
No Matches
unix/io.cpp
Go to the documentation of this file.
1/*
2* This program source code file is part of KiCad, a free EDA CAD application.
3*
4* Copyright (C) 2023 Mark Roszko <[email protected]>
5 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
6*
7* This program is free software: you can redistribute it and/or modify it
8* under the terms of the GNU General Public License as published by the
9* Free Software Foundation, either version 3 of the License, or (at your
10* option) any later version.
11*
12* This program is distributed in the hope that it will be useful, but
13* WITHOUT ANY WARRANTY; without even the implied warranty of
14* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15* General Public License for more details.
16*
17* You should have received a copy of the GNU General Public License along
18* with this program. If not, see <http://www.gnu.org/licenses/>.
19*/
20
21#include <kiplatform/io.h>
22
23#include <wx/crt.h>
24#include <wx/string.h>
25#include <wx/filename.h>
26
27#include <cerrno>
28#include <climits>
29#include <cstdio>
30#include <cstring>
31#include <dirent.h>
32#include <fcntl.h>
33#include <fnmatch.h>
34#include <string>
35#include <sys/mman.h>
36#include <sys/stat.h>
37#include <unistd.h>
38
39FILE* KIPLATFORM::IO::SeqFOpen( const wxString& aPath, const wxString& aMode )
40{
41 FILE* fp = wxFopen( aPath, aMode );
42
43 if( fp )
44 {
45 if( posix_fadvise( fileno( fp ), 0, 0, POSIX_FADV_SEQUENTIAL ) != 0 )
46 {
47 fclose( fp );
48 fp = nullptr;
49 }
50 }
51
52 return fp;
53}
54
55bool KIPLATFORM::IO::DuplicatePermissions( const wxString &aSrc, const wxString &aDest )
56{
57 struct stat sourceStat;
58 if( stat( aSrc.fn_str(), &sourceStat ) == 0 )
59 {
60 mode_t permissions = sourceStat.st_mode & ( S_IRWXU | S_IRWXG | S_IRWXO );
61 if( chmod( aDest.fn_str(), permissions ) == 0 )
62 {
63 return true;
64 }
65 else
66 {
67 // Handle error
68 return false;
69 }
70 }
71 else
72 {
73 // Handle error
74 return false;
75 }
76}
77
78bool KIPLATFORM::IO::MakeWriteable( const wxString& aFilePath )
79{
80 struct stat fileStat;
81 if( stat( aFilePath.fn_str(), &fileStat ) == 0 )
82 {
83 // Add user write permission to existing permissions
84 mode_t newPermissions = fileStat.st_mode | S_IWUSR;
85 if( chmod( aFilePath.fn_str(), newPermissions ) == 0 )
86 {
87 return true;
88 }
89 }
90 return false;
91}
92
93
95{
96 // POSIX rename(2) preserves the target directory entry's inode metadata for the new
97 // file, and DuplicatePermissions(target, temp) carries mode bits across the rename.
98 // No attributes above mode need to be snapshotted here.
99 return TARGET_ATTRS{};
100}
101
102
104{
105 return true;
106}
107
108
109bool KIPLATFORM::IO::IsFileHidden( const wxString& aFileName )
110{
111 wxFileName fn( aFileName );
112
113 return fn.GetName().StartsWith( wxT( "." ) );
114}
115
116
117void KIPLATFORM::IO::LongPathAdjustment( wxFileName& aFilename )
118{
119 // no-op
120}
121
122
123long long KIPLATFORM::IO::TimestampDir( const wxString& aDirPath, const wxString& aFilespec )
124{
125 long long timestamp = 0;
126
127 std::string pattern( aFilespec.fn_str() );
128 std::string dir_path( aDirPath.fn_str() );
129
130 DIR* dir = opendir( dir_path.c_str() );
131
132 if( dir )
133 {
134 for( dirent* dir_entry = readdir( dir ); dir_entry; dir_entry = readdir( dir ) )
135 {
136 // FNM_PERIOD skips dotfiles (hidden files), FNM_CASEFOLD for case-insensitive match
137 if( fnmatch( pattern.c_str(), dir_entry->d_name, FNM_CASEFOLD | FNM_PERIOD ) != 0 )
138 continue;
139
140 std::string entry_path = dir_path + '/' + dir_entry->d_name;
141 struct stat entry_stat;
142
143 if( lstat( entry_path.c_str(), &entry_stat ) == 0 )
144 {
145 // Follow symlinks to get the actual file's timestamp
146 if( S_ISLNK( entry_stat.st_mode ) )
147 {
148 char buffer[PATH_MAX + 1];
149 ssize_t pathLen = readlink( entry_path.c_str(), buffer, PATH_MAX );
150
151 if( pathLen > 0 )
152 {
153 struct stat linked_stat;
154 buffer[pathLen] = '\0';
155 std::string linked_path = dir_path + '/' + buffer;
156
157 if( lstat( linked_path.c_str(), &linked_stat ) == 0 )
158 entry_stat = linked_stat;
159 }
160 }
161
162 if( S_ISREG( entry_stat.st_mode ) )
163 {
164 timestamp += entry_stat.st_mtime * 1000;
165 timestamp += entry_stat.st_size;
166 }
167 }
168 else
169 {
170 // If we couldn't stat the file, use the name hash
171 timestamp += (signed) std::hash<std::string>{}( std::string( dir_entry->d_name ) );
172 }
173 }
174
175 closedir( dir );
176 }
177
178 return timestamp;
179}
180
181
183{
184 if( !aFp )
185 return false;
186
187 if( std::fflush( aFp ) != 0 )
188 return false;
189
190 int fd = fileno( aFp );
191
192 if( fd < 0 )
193 return false;
194
195 return fsync( fd ) == 0;
196}
197
198
200{
201 int fd = open( aFileName.fn_str(), O_RDONLY );
202
203 if( fd < 0 )
204 {
205 throw std::runtime_error( std::string( "Cannot open file: " )
206 + aFileName.ToStdString() );
207 }
208
209 struct stat st;
210
211 if( fstat( fd, &st ) != 0 )
212 {
213 close( fd );
214 throw std::runtime_error( std::string( "Cannot stat file: " )
215 + aFileName.ToStdString() );
216 }
217
218 m_size = static_cast<size_t>( st.st_size );
219
220 if( m_size == 0 )
221 {
222 close( fd );
223 return;
224 }
225
226 void* ptr = mmap( nullptr, m_size, PROT_READ, MAP_PRIVATE, fd, 0 );
227 close( fd );
228
229 if( ptr == MAP_FAILED )
230 {
231 readIntoBuffer( aFileName );
232 return;
233 }
234
235 madvise( ptr, m_size, MADV_SEQUENTIAL );
236 m_data = static_cast<const uint8_t*>( ptr );
237 m_isMapped = true;
238}
239
240
242{
243 if( m_isMapped && m_data )
244 munmap( const_cast<uint8_t*>( m_data ), m_size );
245}
MAPPED_FILE(const wxString &aFileName)
Definition unix/io.cpp:199
void readIntoBuffer(const wxString &aFileName)
const uint8_t * m_data
Definition io.h:56
void LongPathAdjustment(wxFileName &aFilename)
Adjusts a filename to be a long path compatible.
Definition unix/io.cpp:117
FILE * SeqFOpen(const wxString &aPath, const wxString &mode)
Opens the file like fopen but sets flags (if available) for sequential read hinting.
Definition unix/io.cpp:39
TARGET_ATTRS CaptureTargetAttributes(const wxString &aPath)
Captures attributes of an existing aPath that must survive an atomic rename.
Definition unix/io.cpp:94
bool DuplicatePermissions(const wxString &aSrc, const wxString &aDest)
Duplicates the file security data from one file to another ensuring that they are the same between bo...
Definition unix/io.cpp:55
bool IsFileHidden(const wxString &aFileName)
Helper function to determine the status of the 'Hidden' file attribute.
Definition unix/io.cpp:109
bool MakeWriteable(const wxString &aFilePath)
Ensures that a file has write permissions.
Definition unix/io.cpp:78
bool ApplyTargetAttributes(const wxString &aPath, const TARGET_ATTRS &aAttrs)
Re-applies attributes previously captured by CaptureTargetAttributes.
Definition unix/io.cpp:103
long long TimestampDir(const wxString &aDirPath, const wxString &aFilespec)
Computes a hash of modification times and sizes for files matching a pattern.
Definition unix/io.cpp:123
bool FlushToDisk(FILE *aFp)
Flushes user-space buffers for aFp and forces the kernel/filesystem to commit the file's data blocks ...
Definition unix/io.cpp:182
Opaque snapshot of filesystem attributes that MakeWriteable may alter and that the atomic rename sequ...
Definition io.h:209