1 //////////////////////////////////////////////////////////////////////// 2 // 3 // Copyright (C) 1996-2021 The Octave Project Developers 4 // 5 // See the file COPYRIGHT.md in the top-level directory of this 6 // distribution or <https://octave.org/copyright/>. 7 // 8 // This file is part of Octave. 9 // 10 // Octave is free software: you can redistribute it and/or modify it 11 // under the terms of the GNU General Public License as published by 12 // the Free Software Foundation, either version 3 of the License, or 13 // (at your option) any later version. 14 // 15 // Octave is distributed in the hope that it will be useful, but 16 // WITHOUT ANY WARRANTY; without even the implied warranty of 17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 // GNU General Public License for more details. 19 // 20 // You should have received a copy of the GNU General Public License 21 // along with Octave; see the file COPYING. If not, see 22 // <https://www.gnu.org/licenses/>. 23 // 24 //////////////////////////////////////////////////////////////////////// 25 26 #if defined (HAVE_CONFIG_H) 27 # include "config.h" 28 #endif 29 30 #include <ctime> 31 #include <cerrno> 32 #include <cstring> 33 34 #include "file-ops.h" 35 #include "file-stat.h" 36 #include "stat-wrappers.h" 37 #include "strmode-wrapper.h" 38 39 #if defined (OCTAVE_USE_WINDOWS_API) 40 # include "lo-regexp.h" 41 # include "oct-env.h" 42 #endif 43 44 namespace octave 45 { 46 namespace sys 47 { 48 // FIXME: the is_* and mode_as_string functions are only valid 49 // for initialized objects. If called for an object that is not 50 // initialized, they should throw an exception. 51 52 bool is_blk(void) const53 base_file_stat::is_blk (void) const 54 { 55 return exists () && is_blk (m_mode); 56 } 57 58 bool is_chr(void) const59 base_file_stat::is_chr (void) const 60 { 61 return exists () && is_chr (m_mode); 62 } 63 64 bool is_dir(void) const65 base_file_stat::is_dir (void) const 66 { 67 return exists () && is_dir (m_mode); 68 } 69 70 bool is_fifo(void) const71 base_file_stat::is_fifo (void) const 72 { 73 return exists () && is_fifo (m_mode); 74 } 75 76 bool is_lnk(void) const77 base_file_stat::is_lnk (void) const 78 { 79 return exists () && is_lnk (m_mode); 80 } 81 82 bool is_reg(void) const83 base_file_stat::is_reg (void) const 84 { 85 return exists () && is_reg (m_mode); 86 } 87 88 bool is_sock(void) const89 base_file_stat::is_sock (void) const 90 { 91 return exists () && is_sock (m_mode); 92 } 93 94 bool is_blk(mode_t mode)95 base_file_stat::is_blk (mode_t mode) 96 { 97 return octave_is_blk_wrapper (mode); 98 } 99 100 bool is_chr(mode_t mode)101 base_file_stat::is_chr (mode_t mode) 102 { 103 return octave_is_chr_wrapper (mode); 104 } 105 106 bool is_dir(mode_t mode)107 base_file_stat::is_dir (mode_t mode) 108 { 109 return octave_is_dir_wrapper (mode); 110 } 111 112 bool is_fifo(mode_t mode)113 base_file_stat::is_fifo (mode_t mode) 114 { 115 return octave_is_fifo_wrapper (mode); 116 } 117 118 bool is_lnk(mode_t mode)119 base_file_stat::is_lnk (mode_t mode) 120 { 121 return octave_is_lnk_wrapper (mode); 122 } 123 124 bool is_reg(mode_t mode)125 base_file_stat::is_reg (mode_t mode) 126 { 127 return octave_is_reg_wrapper (mode); 128 } 129 130 bool is_sock(mode_t mode)131 base_file_stat::is_sock (mode_t mode) 132 { 133 return octave_is_sock_wrapper (mode); 134 } 135 136 bool have_struct_stat_st_rdev(void)137 base_file_stat::have_struct_stat_st_rdev (void) 138 { 139 return ::octave_have_struct_stat_st_rdev (); 140 } 141 142 bool have_struct_stat_st_blksize(void)143 base_file_stat::have_struct_stat_st_blksize (void) 144 { 145 return octave_have_struct_stat_st_blksize (); 146 } 147 148 bool have_struct_stat_st_blocks(void)149 base_file_stat::have_struct_stat_st_blocks (void) 150 { 151 return octave_have_struct_stat_st_blocks (); 152 } 153 154 std::string mode_as_string(void) const155 base_file_stat::mode_as_string (void) const 156 { 157 char buf[12]; 158 159 octave_strmode_wrapper (m_mode, buf); 160 161 return std::string (buf); 162 } 163 164 // Has FILE been modified since TIME? Returns 1 for yes, 0 for no, 165 // and -1 for any error. 166 167 int is_newer(const std::string & file,const sys::time & time)168 base_file_stat::is_newer (const std::string& file, 169 const sys::time& time) 170 { 171 file_stat fs (file); 172 173 return fs ? fs.is_newer (time) : -1; 174 } 175 176 // Private stuff: 177 file_stat(const std::string & n,bool fl)178 file_stat::file_stat (const std::string& n, bool fl) 179 : base_file_stat (), file_name (n), follow_links (fl) 180 { 181 if (! file_name.empty ()) 182 update_internal (); 183 } 184 ~file_stat()185 file_stat::~file_stat () { } 186 187 void update_internal(bool force)188 file_stat::update_internal (bool force) 189 { 190 if (! initialized || force) 191 { 192 initialized = false; 193 fail = false; 194 195 std::string full_file_name = sys::file_ops::tilde_expand (file_name); 196 197 #if defined (OCTAVE_USE_WINDOWS_API) 198 full_file_name = sys::env::make_absolute (full_file_name); 199 200 // Remove trailing slashes 201 while (full_file_name.length () > 1 202 && sys::file_ops::is_dir_sep (full_file_name.back ())) 203 full_file_name.pop_back (); 204 205 // If path is a root (like "C:" or "\\SERVER\share"), add a 206 // trailing backslash. 207 // FIXME: This pattern does not match all possible UNC roots: 208 // https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-dtyp/62e862f4-2a51-452e-8eeb-dc4ff5ee33cc 209 static regexp pat (R"(^\\\\[\w.-]+\\[\w\$-]+$)"); 210 if ((full_file_name.length () == 2 && full_file_name[1] == ':') 211 || (full_file_name.length () > 4 && full_file_name[0] == '\\' 212 && full_file_name[1] == '\\' && pat.is_match (full_file_name))) 213 full_file_name.push_back ('\\'); 214 #endif 215 216 const char *cname = full_file_name.c_str (); 217 218 time_t sys_atime, sys_mtime, sys_ctime; 219 220 int status 221 = (follow_links 222 ? octave_stat_wrapper (cname, &m_mode, &m_ino, &m_dev, 223 &m_nlink, &m_uid, &m_gid, &m_size, 224 &sys_atime, &sys_mtime, &sys_ctime, 225 &m_rdev, &m_blksize, &m_blocks) 226 : octave_lstat_wrapper (cname, &m_mode, &m_ino, &m_dev, 227 &m_nlink, &m_uid, &m_gid, &m_size, 228 &sys_atime, &sys_mtime, &sys_ctime, 229 &m_rdev, &m_blksize, &m_blocks)); 230 231 if (status < 0) 232 { 233 fail = true; 234 errmsg = std::strerror (errno); 235 } 236 else 237 { 238 m_atime = sys::time (sys_atime); 239 m_mtime = sys::time (sys_mtime); 240 m_ctime = sys::time (sys_ctime); 241 } 242 243 initialized = true; 244 } 245 } 246 247 void update_internal(bool force)248 file_fstat::update_internal (bool force) 249 { 250 if (! initialized || force) 251 { 252 initialized = false; 253 fail = false; 254 255 time_t sys_atime, sys_mtime, sys_ctime; 256 257 int status 258 = octave_fstat_wrapper (fid, &m_mode, &m_ino, &m_dev, 259 &m_nlink, &m_uid, &m_gid, &m_size, 260 &sys_atime, &sys_mtime, &sys_ctime, 261 &m_rdev, &m_blksize, &m_blocks); 262 263 if (status < 0) 264 { 265 fail = true; 266 errmsg = std::strerror (errno); 267 } 268 else 269 { 270 m_atime = sys::time (sys_atime); 271 m_mtime = sys::time (sys_mtime); 272 m_ctime = sys::time (sys_ctime); 273 } 274 275 initialized = true; 276 } 277 } 278 } 279 } 280