1///////////////////////////////////////////////////////////////////////////// 2// Name: file.cpp 3// Purpose: wxFile - encapsulates low-level "file descriptor" 4// wxTempFile 5// Author: Vadim Zeitlin 6// Modified by: 7// Created: 29/01/98 8// RCS-ID: $Id: file.cpp 42876 2006-10-31 23:29:02Z SN $ 9// Copyright: (c) 1998 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr> 10// Licence: wxWindows licence 11///////////////////////////////////////////////////////////////////////////// 12 13// ---------------------------------------------------------------------------- 14// headers 15// ---------------------------------------------------------------------------- 16 17// For compilers that support precompilation, includes "wx.h". 18#include "wx/wxprec.h" 19 20#ifdef __BORLANDC__ 21 #pragma hdrstop 22#endif 23 24#if wxUSE_FILE 25 26// standard 27#if defined(__WXMSW__) && !defined(__GNUWIN32__) && !defined(__WXMICROWIN__) && !defined(__WXWINCE__) 28 29#ifndef __SALFORDC__ 30 #define WIN32_LEAN_AND_MEAN 31 #define NOSERVICE 32 #define NOIME 33 #define NOATOM 34 #define NOGDI 35 #define NOGDICAPMASKS 36 #define NOMETAFILE 37 #define NOMINMAX 38 #define NOMSG 39 #define NOOPENFILE 40 #define NORASTEROPS 41 #define NOSCROLL 42 #define NOSOUND 43 #define NOSYSMETRICS 44 #define NOTEXTMETRIC 45 #define NOWH 46 #define NOCOMM 47 #define NOKANJI 48 #define NOCRYPT 49 #define NOMCX 50#endif 51 52#elif defined(__WXMSW__) && defined(__WXWINCE__) 53 #include "wx/msw/missing.h" 54#elif (defined(__OS2__)) 55 #include <io.h> 56#elif (defined(__UNIX__) || defined(__GNUWIN32__)) 57 #include <unistd.h> 58 #include <time.h> 59 #include <sys/stat.h> 60 #ifdef __GNUWIN32__ 61 #include "wx/msw/wrapwin.h" 62 #endif 63#elif defined(__DOS__) 64 #if defined(__WATCOMC__) 65 #include <io.h> 66 #elif defined(__DJGPP__) 67 #include <io.h> 68 #include <unistd.h> 69 #include <stdio.h> 70 #else 71 #error "Please specify the header with file functions declarations." 72 #endif 73#elif (defined(__WXSTUBS__)) 74 // Have to ifdef this for different environments 75 #include <io.h> 76#elif (defined(__WXMAC__)) 77#if __MSL__ < 0x6000 78 int access( const char *path, int mode ) { return 0 ; } 79#else 80 int _access( const char *path, int mode ) { return 0 ; } 81#endif 82 char* mktemp( char * path ) { return path ;} 83 #include <stat.h> 84 #include <unistd.h> 85#else 86 #error "Please specify the header with file functions declarations." 87#endif //Win/UNIX 88 89#include <stdio.h> // SEEK_xxx constants 90 91// Windows compilers don't have these constants 92#ifndef W_OK 93 enum 94 { 95 F_OK = 0, // test for existence 96 X_OK = 1, // execute permission 97 W_OK = 2, // write 98 R_OK = 4 // read 99 }; 100#endif // W_OK 101 102#ifdef __SALFORDC__ 103 #include <unix.h> 104#endif 105 106// some broken compilers don't have 3rd argument in open() and creat() 107#ifdef __SALFORDC__ 108 #define ACCESS(access) 109 #define stat _stat 110#else // normal compiler 111 #define ACCESS(access) , (access) 112#endif // Salford C 113 114// wxWidgets 115#ifndef WX_PRECOMP 116 #include "wx/string.h" 117 #include "wx/intl.h" 118 #include "wx/log.h" 119#endif // !WX_PRECOMP 120 121#include "wx/filename.h" 122#include "wx/file.h" 123#include "wx/filefn.h" 124 125// there is no distinction between text and binary files under Unix, so define 126// O_BINARY as 0 if the system headers don't do it already 127#if defined(__UNIX__) && !defined(O_BINARY) 128 #define O_BINARY (0) 129#endif //__UNIX__ 130 131#ifdef __WXMSW__ 132 #include "wx/msw/mslu.h" 133#endif 134 135#ifdef __WXWINCE__ 136 #include "wx/msw/private.h" 137#endif 138 139#ifndef MAX_PATH 140 #define MAX_PATH 512 141#endif 142 143// ============================================================================ 144// implementation of wxFile 145// ============================================================================ 146 147// ---------------------------------------------------------------------------- 148// static functions 149// ---------------------------------------------------------------------------- 150 151bool wxFile::Exists(const wxChar *name) 152{ 153 return wxFileExists(name); 154} 155 156bool wxFile::Access(const wxChar *name, OpenMode mode) 157{ 158 int how; 159 160 switch ( mode ) 161 { 162 default: 163 wxFAIL_MSG(wxT("bad wxFile::Access mode parameter.")); 164 // fall through 165 166 case read: 167 how = R_OK; 168 break; 169 170 case write: 171 how = W_OK; 172 break; 173 174 case read_write: 175 how = R_OK | W_OK; 176 break; 177 } 178 179 return wxAccess(name, how) == 0; 180} 181 182// ---------------------------------------------------------------------------- 183// opening/closing 184// ---------------------------------------------------------------------------- 185 186// ctors 187wxFile::wxFile(const wxChar *szFileName, OpenMode mode) 188{ 189 m_fd = fd_invalid; 190 m_error = false; 191 192 Open(szFileName, mode); 193} 194 195// create the file, fail if it already exists and bOverwrite 196bool wxFile::Create(const wxChar *szFileName, bool bOverwrite, int accessMode) 197{ 198 // if bOverwrite we create a new file or truncate the existing one, 199 // otherwise we only create the new file and fail if it already exists 200#if defined(__WXMAC__) && !defined(__UNIX__) && !wxUSE_UNICODE 201 // Dominic Mazzoni [dmazzoni+@cs.cmu.edu] reports that open is still broken on the mac, so we replace 202 // int fd = open( szFileName , O_CREAT | (bOverwrite ? O_TRUNC : O_EXCL), access); 203 int fd = creat( szFileName , accessMode); 204#else 205 int fd = wxOpen( szFileName, 206 O_BINARY | O_WRONLY | O_CREAT | 207 (bOverwrite ? O_TRUNC : O_EXCL) 208 ACCESS(accessMode) ); 209#endif 210 if ( fd == -1 ) 211 { 212 wxLogSysError(_("can't create file '%s'"), szFileName); 213 return false; 214 } 215 216 Attach(fd); 217 return true; 218} 219 220// open the file 221bool wxFile::Open(const wxChar *szFileName, OpenMode mode, int accessMode) 222{ 223 int flags = O_BINARY; 224 225 switch ( mode ) 226 { 227 case read: 228 flags |= O_RDONLY; 229 break; 230 231 case write_append: 232 if ( wxFile::Exists(szFileName) ) 233 { 234 flags |= O_WRONLY | O_APPEND; 235 break; 236 } 237 //else: fall through as write_append is the same as write if the 238 // file doesn't exist 239 240 case write: 241 flags |= O_WRONLY | O_CREAT | O_TRUNC; 242 break; 243 244 case write_excl: 245 flags |= O_WRONLY | O_CREAT | O_EXCL; 246 break; 247 248 case read_write: 249 flags |= O_RDWR; 250 break; 251 } 252 253#ifdef __WINDOWS__ 254 // only read/write bits for "all" are supported by this function under 255 // Windows, and VC++ 8 returns EINVAL if any other bits are used in 256 // accessMode, so clear them as they have at best no effect anyhow 257 accessMode &= wxS_IRUSR | wxS_IWUSR; 258#endif // __WINDOWS__ 259 260 int fd = wxOpen( szFileName, flags ACCESS(accessMode)); 261 262 if ( fd == -1 ) 263 { 264 wxLogSysError(_("can't open file '%s'"), szFileName); 265 return false; 266 } 267 268 Attach(fd); 269 return true; 270} 271 272// close 273bool wxFile::Close() 274{ 275 if ( IsOpened() ) { 276 if (wxClose(m_fd) == -1) 277 { 278 wxLogSysError(_("can't close file descriptor %d"), m_fd); 279 m_fd = fd_invalid; 280 return false; 281 } 282 else 283 m_fd = fd_invalid; 284 } 285 286 return true; 287} 288 289// ---------------------------------------------------------------------------- 290// read/write 291// ---------------------------------------------------------------------------- 292 293// read 294ssize_t wxFile::Read(void *pBuf, size_t nCount) 295{ 296 wxCHECK( (pBuf != NULL) && IsOpened(), 0 ); 297 298 ssize_t iRc = wxRead(m_fd, pBuf, nCount); 299 300 if ( iRc == -1 ) 301 { 302 wxLogSysError(_("can't read from file descriptor %d"), m_fd); 303 return wxInvalidOffset; 304 } 305 306 return iRc; 307} 308 309// write 310size_t wxFile::Write(const void *pBuf, size_t nCount) 311{ 312 wxCHECK( (pBuf != NULL) && IsOpened(), 0 ); 313 314 ssize_t iRc = wxWrite(m_fd, pBuf, nCount); 315 316 if ( iRc == -1 ) 317 { 318 wxLogSysError(_("can't write to file descriptor %d"), m_fd); 319 m_error = true; 320 iRc = 0; 321 } 322 323 return iRc; 324} 325 326// flush 327bool wxFile::Flush() 328{ 329#ifdef HAVE_FSYNC 330 // fsync() only works on disk files and returns errors for pipes, don't 331 // call it then 332 if ( IsOpened() && GetKind() == wxFILE_KIND_DISK ) 333 { 334 if ( wxFsync(m_fd) == -1 ) 335 { 336 wxLogSysError(_("can't flush file descriptor %d"), m_fd); 337 return false; 338 } 339 } 340#endif // HAVE_FSYNC 341 342 return true; 343} 344 345// ---------------------------------------------------------------------------- 346// seek 347// ---------------------------------------------------------------------------- 348 349// seek 350wxFileOffset wxFile::Seek(wxFileOffset ofs, wxSeekMode mode) 351{ 352 wxASSERT_MSG( IsOpened(), _T("can't seek on closed file") ); 353 wxCHECK_MSG( ofs != wxInvalidOffset || mode != wxFromStart, 354 wxInvalidOffset, 355 _T("invalid absolute file offset") ); 356 357 int origin; 358 switch ( mode ) { 359 default: 360 wxFAIL_MSG(_("unknown seek origin")); 361 362 case wxFromStart: 363 origin = SEEK_SET; 364 break; 365 366 case wxFromCurrent: 367 origin = SEEK_CUR; 368 break; 369 370 case wxFromEnd: 371 origin = SEEK_END; 372 break; 373 } 374 375 wxFileOffset iRc = wxSeek(m_fd, ofs, origin); 376 if ( iRc == wxInvalidOffset ) 377 { 378 wxLogSysError(_("can't seek on file descriptor %d"), m_fd); 379 } 380 381 return iRc; 382} 383 384// get current file offset 385wxFileOffset wxFile::Tell() const 386{ 387 wxASSERT( IsOpened() ); 388 389 wxFileOffset iRc = wxTell(m_fd); 390 if ( iRc == wxInvalidOffset ) 391 { 392 wxLogSysError(_("can't get seek position on file descriptor %d"), m_fd); 393 } 394 395 return iRc; 396} 397 398// get current file length 399wxFileOffset wxFile::Length() const 400{ 401 wxASSERT( IsOpened() ); 402 403 wxFileOffset iRc = Tell(); 404 if ( iRc != wxInvalidOffset ) { 405 // have to use const_cast :-( 406 wxFileOffset iLen = ((wxFile *)this)->SeekEnd(); 407 if ( iLen != wxInvalidOffset ) { 408 // restore old position 409 if ( ((wxFile *)this)->Seek(iRc) == wxInvalidOffset ) { 410 // error 411 iLen = wxInvalidOffset; 412 } 413 } 414 415 iRc = iLen; 416 } 417 418 if ( iRc == wxInvalidOffset ) 419 { 420 wxLogSysError(_("can't find length of file on file descriptor %d"), m_fd); 421 } 422 423 return iRc; 424} 425 426// is end of file reached? 427bool wxFile::Eof() const 428{ 429 wxASSERT( IsOpened() ); 430 431 wxFileOffset iRc; 432 433#if defined(__DOS__) || defined(__UNIX__) || defined(__GNUWIN32__) || defined( __MWERKS__ ) || defined(__SALFORDC__) 434 // @@ this doesn't work, of course, on unseekable file descriptors 435 wxFileOffset ofsCur = Tell(), 436 ofsMax = Length(); 437 if ( ofsCur == wxInvalidOffset || ofsMax == wxInvalidOffset ) 438 iRc = wxInvalidOffset; 439 else 440 iRc = ofsCur == ofsMax; 441#else // Windows and "native" compiler 442 iRc = wxEof(m_fd); 443#endif // Windows/Unix 444 445 if ( iRc == 1) 446 {} 447 else if ( iRc == 0 ) 448 return false; 449 else if ( iRc == wxInvalidOffset ) 450 wxLogSysError(_("can't determine if the end of file is reached on descriptor %d"), m_fd); 451 else 452 wxFAIL_MSG(_("invalid eof() return value.")); 453 454 return true; 455} 456 457// ============================================================================ 458// implementation of wxTempFile 459// ============================================================================ 460 461// ---------------------------------------------------------------------------- 462// construction 463// ---------------------------------------------------------------------------- 464 465wxTempFile::wxTempFile(const wxString& strName) 466{ 467 Open(strName); 468} 469 470bool wxTempFile::Open(const wxString& strName) 471{ 472 // we must have an absolute filename because otherwise CreateTempFileName() 473 // would create the temp file in $TMP (i.e. the system standard location 474 // for the temp files) which might be on another volume/drive/mount and 475 // wxRename()ing it later to m_strName from Commit() would then fail 476 // 477 // with the absolute filename, the temp file is created in the same 478 // directory as this one which ensures that wxRename() may work later 479 wxFileName fn(strName); 480 if ( !fn.IsAbsolute() ) 481 { 482 fn.Normalize(wxPATH_NORM_ABSOLUTE); 483 } 484 485 m_strName = fn.GetFullPath(); 486 487 m_strTemp = wxFileName::CreateTempFileName(m_strName, &m_file); 488 489 if ( m_strTemp.empty() ) 490 { 491 // CreateTempFileName() failed 492 return false; 493 } 494 495#ifdef __UNIX__ 496 // the temp file should have the same permissions as the original one 497 mode_t mode; 498 499 wxStructStat st; 500 if ( stat( (const char*) m_strName.fn_str(), &st) == 0 ) 501 { 502 mode = st.st_mode; 503 } 504 else 505 { 506 // file probably didn't exist, just give it the default mode _using_ 507 // user's umask (new files creation should respect umask) 508 mode_t mask = umask(0777); 509 mode = 0666 & ~mask; 510 umask(mask); 511 } 512 513 if ( chmod( (const char*) m_strTemp.fn_str(), mode) == -1 ) 514 { 515#ifndef __OS2__ 516 wxLogSysError(_("Failed to set temporary file permissions")); 517#endif 518 } 519#endif // Unix 520 521 return true; 522} 523 524// ---------------------------------------------------------------------------- 525// destruction 526// ---------------------------------------------------------------------------- 527 528wxTempFile::~wxTempFile() 529{ 530 if ( IsOpened() ) 531 Discard(); 532} 533 534bool wxTempFile::Commit() 535{ 536 m_file.Close(); 537 538 if ( wxFile::Exists(m_strName) && wxRemove(m_strName) != 0 ) { 539 wxLogSysError(_("can't remove file '%s'"), m_strName.c_str()); 540 return false; 541 } 542 543 if ( !wxRenameFile(m_strTemp, m_strName) ) { 544 wxLogSysError(_("can't commit changes to file '%s'"), m_strName.c_str()); 545 return false; 546 } 547 548 return true; 549} 550 551void wxTempFile::Discard() 552{ 553 m_file.Close(); 554 if ( wxRemove(m_strTemp) != 0 ) 555 wxLogSysError(_("can't remove temporary file '%s'"), m_strTemp.c_str()); 556} 557 558#endif // wxUSE_FILE 559 560