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 |
|
151 |
bool wxFile::Exists(const wxChar *name) |
152 |
{ |
153 |
return wxFileExists(name); |
154 |
} |
155 |
|
156 |
bool 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 |
187 |
wxFile::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 |
196 |
bool 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 |
221 |
bool 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 |
273 |
bool 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 |
294 |
ssize_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 |
310 |
size_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 |
327 |
bool 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 |
350 |
wxFileOffset 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 |
385 |
wxFileOffset 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 |
399 |
wxFileOffset 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? |
427 |
bool 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 |
|
465 |
wxTempFile::wxTempFile(const wxString& strName) |
466 |
{ |
467 |
Open(strName); |
468 |
} |
469 |
|
470 |
bool 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 |
|
528 |
wxTempFile::~wxTempFile() |
529 |
{ |
530 |
if ( IsOpened() ) |
531 |
Discard(); |
532 |
} |
533 |
|
534 |
bool 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 |
|
551 |
void 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 |
|