Hungarian translation update
[ntk/apt.git] / apt-pkg / contrib / fileutl.cc
CommitLineData
578bfd0a
AL
1// -*- mode: cpp; mode: fold -*-
2// Description /*{{{*/
7da2b375 3// $Id: fileutl.cc,v 1.42 2002/09/14 05:29:22 jgg Exp $
578bfd0a
AL
4/* ######################################################################
5
6 File Utilities
7
8 CopyFile - Buffered copy of a single file
9 GetLock - dpkg compatible lock file manipulation (fcntl)
10
614adaa0
MV
11 Most of this source is placed in the Public Domain, do with it what
12 you will
7da2b375 13 It was originally written by Jason Gunthorpe <jgg@debian.org>.
578bfd0a 14
614adaa0
MV
15 The exception is RunScripts() it is under the GPLv2
16
578bfd0a
AL
17 ##################################################################### */
18 /*}}}*/
19// Include Files /*{{{*/
094a497d
AL
20#include <apt-pkg/fileutl.h>
21#include <apt-pkg/error.h>
b2e465d6 22#include <apt-pkg/sptr.h>
75ef8f14 23#include <apt-pkg/configuration.h>
b2e465d6
AL
24
25#include <apti18n.h>
578bfd0a 26
152ab79e 27#include <cstdlib>
4f333a8b
MV
28#include <cstring>
29
4d055c05 30#include <iostream>
578bfd0a 31#include <unistd.h>
2c206aa4 32#include <fcntl.h>
578bfd0a 33#include <sys/stat.h>
578bfd0a 34#include <sys/types.h>
cc2313b7 35#include <sys/time.h>
1ae93c94 36#include <sys/wait.h>
54676e1a 37#include <signal.h>
65a1e968 38#include <errno.h>
75ef8f14 39#include <set>
578bfd0a
AL
40 /*}}}*/
41
4d055c05
AL
42using namespace std;
43
614adaa0
MV
44// RunScripts - Run a set of scripts from a configuration subtree /*{{{*/
45// ---------------------------------------------------------------------
46/* */
47bool RunScripts(const char *Cnf)
48{
49 Configuration::Item const *Opts = _config->Tree(Cnf);
50 if (Opts == 0 || Opts->Child == 0)
51 return true;
52 Opts = Opts->Child;
53
54 // Fork for running the system calls
55 pid_t Child = ExecFork();
56
57 // This is the child
58 if (Child == 0)
59 {
60 if (chdir("/tmp/") != 0)
61 _exit(100);
62
63 unsigned int Count = 1;
64 for (; Opts != 0; Opts = Opts->Next, Count++)
65 {
66 if (Opts->Value.empty() == true)
67 continue;
68
69 if (system(Opts->Value.c_str()) != 0)
70 _exit(100+Count);
71 }
72 _exit(0);
73 }
74
75 // Wait for the child
76 int Status = 0;
77 while (waitpid(Child,&Status,0) != Child)
78 {
79 if (errno == EINTR)
80 continue;
81 return _error->Errno("waitpid","Couldn't wait for subprocess");
82 }
83
84 // Restore sig int/quit
85 signal(SIGQUIT,SIG_DFL);
86 signal(SIGINT,SIG_DFL);
87
88 // Check for an error code.
89 if (WIFEXITED(Status) == 0 || WEXITSTATUS(Status) != 0)
90 {
91 unsigned int Count = WEXITSTATUS(Status);
92 if (Count > 100)
93 {
94 Count -= 100;
95 for (; Opts != 0 && Count != 1; Opts = Opts->Next, Count--);
96 _error->Error("Problem executing scripts %s '%s'",Cnf,Opts->Value.c_str());
97 }
98
99 return _error->Error("Sub-process returned an error code");
100 }
101
102 return true;
103}
104 /*}}}*/
105
578bfd0a
AL
106// CopyFile - Buffered copy of a file /*{{{*/
107// ---------------------------------------------------------------------
108/* The caller is expected to set things so that failure causes erasure */
8b89e57f 109bool CopyFile(FileFd &From,FileFd &To)
578bfd0a
AL
110{
111 if (From.IsOpen() == false || To.IsOpen() == false)
112 return false;
113
114 // Buffered copy between fds
b2e465d6 115 SPtrArray<unsigned char> Buf = new unsigned char[64000];
b0db36b1
AL
116 unsigned long Size = From.Size();
117 while (Size != 0)
578bfd0a 118 {
b0db36b1
AL
119 unsigned long ToRead = Size;
120 if (Size > 64000)
121 ToRead = 64000;
122
4a6d5862 123 if (From.Read(Buf,ToRead) == false ||
b0db36b1 124 To.Write(Buf,ToRead) == false)
578bfd0a 125 return false;
b0db36b1
AL
126
127 Size -= ToRead;
578bfd0a
AL
128 }
129
578bfd0a
AL
130 return true;
131}
132 /*}}}*/
133// GetLock - Gets a lock file /*{{{*/
134// ---------------------------------------------------------------------
135/* This will create an empty file of the given name and lock it. Once this
136 is done all other calls to GetLock in any other process will fail with
137 -1. The return result is the fd of the file, the call should call
138 close at some time. */
139int GetLock(string File,bool Errors)
140{
141 int FD = open(File.c_str(),O_RDWR | O_CREAT | O_TRUNC,0640);
142 if (FD < 0)
143 {
b2e465d6
AL
144 // Read only .. cant have locking problems there.
145 if (errno == EROFS)
146 {
147 _error->Warning(_("Not using locking for read only lock file %s"),File.c_str());
148 return dup(0); // Need something for the caller to close
149 }
150
578bfd0a 151 if (Errors == true)
b2e465d6
AL
152 _error->Errno("open",_("Could not open lock file %s"),File.c_str());
153
154 // Feh.. We do this to distinguish the lock vs open case..
155 errno = EPERM;
578bfd0a
AL
156 return -1;
157 }
b2e465d6
AL
158 SetCloseExec(FD,true);
159
578bfd0a
AL
160 // Aquire a write lock
161 struct flock fl;
c71bc556
AL
162 fl.l_type = F_WRLCK;
163 fl.l_whence = SEEK_SET;
164 fl.l_start = 0;
165 fl.l_len = 0;
578bfd0a
AL
166 if (fcntl(FD,F_SETLK,&fl) == -1)
167 {
d89df07a
AL
168 if (errno == ENOLCK)
169 {
b2e465d6
AL
170 _error->Warning(_("Not using locking for nfs mounted lock file %s"),File.c_str());
171 return dup(0); // Need something for the caller to close
d89df07a 172 }
578bfd0a 173 if (Errors == true)
b2e465d6
AL
174 _error->Errno("open",_("Could not get lock %s"),File.c_str());
175
176 int Tmp = errno;
578bfd0a 177 close(FD);
b2e465d6 178 errno = Tmp;
578bfd0a
AL
179 return -1;
180 }
181
182 return FD;
183}
184 /*}}}*/
185// FileExists - Check if a file exists /*{{{*/
186// ---------------------------------------------------------------------
187/* */
188bool FileExists(string File)
189{
190 struct stat Buf;
191 if (stat(File.c_str(),&Buf) != 0)
192 return false;
193 return true;
194}
195 /*}}}*/
196// SafeGetCWD - This is a safer getcwd that returns a dynamic string /*{{{*/
197// ---------------------------------------------------------------------
198/* We return / on failure. */
199string SafeGetCWD()
200{
201 // Stash the current dir.
202 char S[300];
203 S[0] = 0;
7f25bdff 204 if (getcwd(S,sizeof(S)-2) == 0)
578bfd0a 205 return "/";
7f25bdff
AL
206 unsigned int Len = strlen(S);
207 S[Len] = '/';
208 S[Len+1] = 0;
578bfd0a
AL
209 return S;
210}
211 /*}}}*/
8ce4327b
AL
212// flNotDir - Strip the directory from the filename /*{{{*/
213// ---------------------------------------------------------------------
214/* */
215string flNotDir(string File)
216{
217 string::size_type Res = File.rfind('/');
218 if (Res == string::npos)
219 return File;
220 Res++;
221 return string(File,Res,Res - File.length());
222}
223 /*}}}*/
d38b7b3d
AL
224// flNotFile - Strip the file from the directory name /*{{{*/
225// ---------------------------------------------------------------------
171c45bc 226/* Result ends in a / */
d38b7b3d
AL
227string flNotFile(string File)
228{
229 string::size_type Res = File.rfind('/');
230 if (Res == string::npos)
171c45bc 231 return "./";
d38b7b3d
AL
232 Res++;
233 return string(File,0,Res);
234}
235 /*}}}*/
b2e465d6
AL
236// flExtension - Return the extension for the file /*{{{*/
237// ---------------------------------------------------------------------
238/* */
239string flExtension(string File)
240{
241 string::size_type Res = File.rfind('.');
242 if (Res == string::npos)
243 return File;
244 Res++;
245 return string(File,Res,Res - File.length());
246}
247 /*}}}*/
421c8d10
AL
248// flNoLink - If file is a symlink then deref it /*{{{*/
249// ---------------------------------------------------------------------
250/* If the name is not a link then the returned path is the input. */
251string flNoLink(string File)
252{
253 struct stat St;
254 if (lstat(File.c_str(),&St) != 0 || S_ISLNK(St.st_mode) == 0)
255 return File;
256 if (stat(File.c_str(),&St) != 0)
257 return File;
258
259 /* Loop resolving the link. There is no need to limit the number of
260 loops because the stat call above ensures that the symlink is not
261 circular */
262 char Buffer[1024];
263 string NFile = File;
264 while (1)
265 {
266 // Read the link
267 int Res;
268 if ((Res = readlink(NFile.c_str(),Buffer,sizeof(Buffer))) <= 0 ||
269 (unsigned)Res >= sizeof(Buffer))
270 return File;
271
272 // Append or replace the previous path
273 Buffer[Res] = 0;
274 if (Buffer[0] == '/')
275 NFile = Buffer;
276 else
277 NFile = flNotFile(NFile) + Buffer;
278
279 // See if we are done
280 if (lstat(NFile.c_str(),&St) != 0)
281 return File;
282 if (S_ISLNK(St.st_mode) == 0)
283 return NFile;
284 }
285}
286 /*}}}*/
b2e465d6
AL
287// flCombine - Combine a file and a directory /*{{{*/
288// ---------------------------------------------------------------------
289/* If the file is an absolute path then it is just returned, otherwise
290 the directory is pre-pended to it. */
291string flCombine(string Dir,string File)
292{
293 if (File.empty() == true)
294 return string();
295
296 if (File[0] == '/' || Dir.empty() == true)
297 return File;
298 if (File.length() >= 2 && File[0] == '.' && File[1] == '/')
299 return File;
300 if (Dir[Dir.length()-1] == '/')
301 return Dir + File;
302 return Dir + '/' + File;
303}
304 /*}}}*/
3b5421b4
AL
305// SetCloseExec - Set the close on exec flag /*{{{*/
306// ---------------------------------------------------------------------
307/* */
308void SetCloseExec(int Fd,bool Close)
309{
310 if (fcntl(Fd,F_SETFD,(Close == false)?0:FD_CLOEXEC) != 0)
311 {
312 cerr << "FATAL -> Could not set close on exec " << strerror(errno) << endl;
313 exit(100);
314 }
315}
316 /*}}}*/
317// SetNonBlock - Set the nonblocking flag /*{{{*/
318// ---------------------------------------------------------------------
319/* */
320void SetNonBlock(int Fd,bool Block)
321{
0a8a80e5
AL
322 int Flags = fcntl(Fd,F_GETFL) & (~O_NONBLOCK);
323 if (fcntl(Fd,F_SETFL,Flags | ((Block == false)?0:O_NONBLOCK)) != 0)
3b5421b4
AL
324 {
325 cerr << "FATAL -> Could not set non-blocking flag " << strerror(errno) << endl;
326 exit(100);
327 }
328}
329 /*}}}*/
330// WaitFd - Wait for a FD to become readable /*{{{*/
331// ---------------------------------------------------------------------
b2e465d6 332/* This waits for a FD to become readable using select. It is useful for
6d5dd02a
AL
333 applications making use of non-blocking sockets. The timeout is
334 in seconds. */
1084d58a 335bool WaitFd(int Fd,bool write,unsigned long timeout)
3b5421b4
AL
336{
337 fd_set Set;
cc2313b7 338 struct timeval tv;
3b5421b4
AL
339 FD_ZERO(&Set);
340 FD_SET(Fd,&Set);
6d5dd02a
AL
341 tv.tv_sec = timeout;
342 tv.tv_usec = 0;
1084d58a 343 if (write == true)
b0db36b1
AL
344 {
345 int Res;
346 do
347 {
348 Res = select(Fd+1,0,&Set,0,(timeout != 0?&tv:0));
349 }
350 while (Res < 0 && errno == EINTR);
351
352 if (Res <= 0)
353 return false;
1084d58a
AL
354 }
355 else
356 {
b0db36b1
AL
357 int Res;
358 do
359 {
360 Res = select(Fd+1,&Set,0,0,(timeout != 0?&tv:0));
361 }
362 while (Res < 0 && errno == EINTR);
363
364 if (Res <= 0)
365 return false;
cc2313b7 366 }
1084d58a 367
3b5421b4
AL
368 return true;
369}
370 /*}}}*/
54676e1a
AL
371// ExecFork - Magical fork that sanitizes the context before execing /*{{{*/
372// ---------------------------------------------------------------------
373/* This is used if you want to cleanse the environment for the forked
374 child, it fixes up the important signals and nukes all of the fds,
375 otherwise acts like normal fork. */
75ef8f14 376pid_t ExecFork()
54676e1a
AL
377{
378 // Fork off the process
379 pid_t Process = fork();
380 if (Process < 0)
381 {
382 cerr << "FATAL -> Failed to fork." << endl;
383 exit(100);
384 }
385
386 // Spawn the subprocess
387 if (Process == 0)
388 {
389 // Setup the signals
390 signal(SIGPIPE,SIG_DFL);
391 signal(SIGQUIT,SIG_DFL);
392 signal(SIGINT,SIG_DFL);
393 signal(SIGWINCH,SIG_DFL);
394 signal(SIGCONT,SIG_DFL);
395 signal(SIGTSTP,SIG_DFL);
75ef8f14
MV
396
397 set<int> KeepFDs;
398 Configuration::Item const *Opts = _config->Tree("APT::Keep-Fds");
399 if (Opts != 0 && Opts->Child != 0)
400 {
401 Opts = Opts->Child;
402 for (; Opts != 0; Opts = Opts->Next)
403 {
404 if (Opts->Value.empty() == true)
405 continue;
406 int fd = atoi(Opts->Value.c_str());
407 KeepFDs.insert(fd);
408 }
409 }
410
54676e1a
AL
411 // Close all of our FDs - just in case
412 for (int K = 3; K != 40; K++)
75ef8f14
MV
413 {
414 if(KeepFDs.find(K) == KeepFDs.end())
007dc9e0 415 fcntl(K,F_SETFD,FD_CLOEXEC);
75ef8f14 416 }
54676e1a
AL
417 }
418
419 return Process;
420}
421 /*}}}*/
ddc1d8d0
AL
422// ExecWait - Fancy waitpid /*{{{*/
423// ---------------------------------------------------------------------
2c9a72d1 424/* Waits for the given sub process. If Reap is set then no errors are
ddc1d8d0
AL
425 generated. Otherwise a failed subprocess will generate a proper descriptive
426 message */
3826564e 427bool ExecWait(pid_t Pid,const char *Name,bool Reap)
ddc1d8d0
AL
428{
429 if (Pid <= 1)
430 return true;
431
432 // Wait and collect the error code
433 int Status;
434 while (waitpid(Pid,&Status,0) != Pid)
435 {
436 if (errno == EINTR)
437 continue;
438
439 if (Reap == true)
440 return false;
441
db0db9fe 442 return _error->Error(_("Waited for %s but it wasn't there"),Name);
ddc1d8d0
AL
443 }
444
445
446 // Check for an error code.
447 if (WIFEXITED(Status) == 0 || WEXITSTATUS(Status) != 0)
448 {
449 if (Reap == true)
450 return false;
451 if (WIFSIGNALED(Status) != 0 && WTERMSIG(Status) == SIGSEGV)
b2e465d6 452 return _error->Error(_("Sub-process %s received a segmentation fault."),Name);
ddc1d8d0
AL
453
454 if (WIFEXITED(Status) != 0)
b2e465d6 455 return _error->Error(_("Sub-process %s returned an error code (%u)"),Name,WEXITSTATUS(Status));
ddc1d8d0 456
b2e465d6 457 return _error->Error(_("Sub-process %s exited unexpectedly"),Name);
ddc1d8d0
AL
458 }
459
460 return true;
461}
462 /*}}}*/
578bfd0a 463
13d87e2e 464// FileFd::Open - Open a file /*{{{*/
578bfd0a
AL
465// ---------------------------------------------------------------------
466/* The most commonly used open mode combinations are given with Mode */
13d87e2e 467bool FileFd::Open(string FileName,OpenMode Mode, unsigned long Perms)
578bfd0a 468{
13d87e2e 469 Close();
1164783d 470 Flags = AutoClose;
578bfd0a
AL
471 switch (Mode)
472 {
473 case ReadOnly:
474 iFd = open(FileName.c_str(),O_RDONLY);
475 break;
476
477 case WriteEmpty:
50b513a1
AL
478 {
479 struct stat Buf;
459681d3 480 if (lstat(FileName.c_str(),&Buf) == 0 && S_ISLNK(Buf.st_mode))
50b513a1
AL
481 unlink(FileName.c_str());
482 iFd = open(FileName.c_str(),O_RDWR | O_CREAT | O_TRUNC,Perms);
483 break;
484 }
578bfd0a
AL
485
486 case WriteExists:
487 iFd = open(FileName.c_str(),O_RDWR);
488 break;
0a8e3465
AL
489
490 case WriteAny:
491 iFd = open(FileName.c_str(),O_RDWR | O_CREAT,Perms);
d38b7b3d 492 break;
f08fcf34
AL
493
494 case WriteTemp:
4decd43c
AL
495 unlink(FileName.c_str());
496 iFd = open(FileName.c_str(),O_RDWR | O_CREAT | O_EXCL,Perms);
f08fcf34 497 break;
578bfd0a
AL
498 }
499
500 if (iFd < 0)
b2e465d6 501 return _error->Errno("open",_("Could not open file %s"),FileName.c_str());
13d87e2e
AL
502
503 this->FileName = FileName;
504 SetCloseExec(iFd,true);
505 return true;
578bfd0a
AL
506}
507 /*}}}*/
8e06abb2 508// FileFd::~File - Closes the file /*{{{*/
578bfd0a
AL
509// ---------------------------------------------------------------------
510/* If the proper modes are selected then we close the Fd and possibly
511 unlink the file on error. */
8e06abb2 512FileFd::~FileFd()
578bfd0a
AL
513{
514 Close();
515}
516 /*}}}*/
8e06abb2 517// FileFd::Read - Read a bit of the file /*{{{*/
578bfd0a 518// ---------------------------------------------------------------------
b0db36b1
AL
519/* We are carefull to handle interruption by a signal while reading
520 gracefully. */
f604cf55 521bool FileFd::Read(void *To,unsigned long Size,unsigned long *Actual)
578bfd0a 522{
b0db36b1
AL
523 int Res;
524 errno = 0;
f604cf55
AL
525 if (Actual != 0)
526 *Actual = 0;
527
b0db36b1 528 do
578bfd0a 529 {
b0db36b1
AL
530 Res = read(iFd,To,Size);
531 if (Res < 0 && errno == EINTR)
532 continue;
533 if (Res < 0)
534 {
535 Flags |= Fail;
b2e465d6 536 return _error->Errno("read",_("Read error"));
b0db36b1 537 }
578bfd0a 538
b0db36b1
AL
539 To = (char *)To + Res;
540 Size -= Res;
f604cf55
AL
541 if (Actual != 0)
542 *Actual += Res;
b0db36b1
AL
543 }
544 while (Res > 0 && Size > 0);
545
546 if (Size == 0)
547 return true;
548
ddc1d8d0 549 // Eof handling
f604cf55 550 if (Actual != 0)
ddc1d8d0
AL
551 {
552 Flags |= HitEof;
553 return true;
554 }
555
b0db36b1 556 Flags |= Fail;
b2e465d6 557 return _error->Error(_("read, still have %lu to read but none left"),Size);
578bfd0a
AL
558}
559 /*}}}*/
8e06abb2 560// FileFd::Write - Write to the file /*{{{*/
578bfd0a
AL
561// ---------------------------------------------------------------------
562/* */
a05599f1 563bool FileFd::Write(const void *From,unsigned long Size)
578bfd0a 564{
b0db36b1
AL
565 int Res;
566 errno = 0;
567 do
578bfd0a 568 {
b0db36b1
AL
569 Res = write(iFd,From,Size);
570 if (Res < 0 && errno == EINTR)
571 continue;
572 if (Res < 0)
573 {
574 Flags |= Fail;
b2e465d6 575 return _error->Errno("write",_("Write error"));
b0db36b1
AL
576 }
577
578 From = (char *)From + Res;
579 Size -= Res;
578bfd0a 580 }
b0db36b1 581 while (Res > 0 && Size > 0);
578bfd0a 582
b0db36b1
AL
583 if (Size == 0)
584 return true;
585
586 Flags |= Fail;
b2e465d6 587 return _error->Error(_("write, still have %lu to write but couldn't"),Size);
578bfd0a
AL
588}
589 /*}}}*/
8e06abb2 590// FileFd::Seek - Seek in the file /*{{{*/
578bfd0a
AL
591// ---------------------------------------------------------------------
592/* */
8e06abb2 593bool FileFd::Seek(unsigned long To)
578bfd0a
AL
594{
595 if (lseek(iFd,To,SEEK_SET) != (signed)To)
596 {
597 Flags |= Fail;
b2e465d6 598 return _error->Error("Unable to seek to %lu",To);
578bfd0a
AL
599 }
600
727f18af
AL
601 return true;
602}
603 /*}}}*/
604// FileFd::Skip - Seek in the file /*{{{*/
605// ---------------------------------------------------------------------
606/* */
607bool FileFd::Skip(unsigned long Over)
608{
609 if (lseek(iFd,Over,SEEK_CUR) < 0)
610 {
611 Flags |= Fail;
b2e465d6 612 return _error->Error("Unable to seek ahead %lu",Over);
727f18af
AL
613 }
614
6d5dd02a
AL
615 return true;
616}
617 /*}}}*/
618// FileFd::Truncate - Truncate the file /*{{{*/
619// ---------------------------------------------------------------------
620/* */
621bool FileFd::Truncate(unsigned long To)
622{
623 if (ftruncate(iFd,To) != 0)
624 {
625 Flags |= Fail;
b2e465d6 626 return _error->Error("Unable to truncate to %lu",To);
6d5dd02a
AL
627 }
628
578bfd0a
AL
629 return true;
630}
631 /*}}}*/
7f25bdff
AL
632// FileFd::Tell - Current seek position /*{{{*/
633// ---------------------------------------------------------------------
634/* */
635unsigned long FileFd::Tell()
636{
637 off_t Res = lseek(iFd,0,SEEK_CUR);
638 if (Res == (off_t)-1)
639 _error->Errno("lseek","Failed to determine the current file position");
640 return Res;
641}
642 /*}}}*/
8e06abb2 643// FileFd::Size - Return the size of the file /*{{{*/
578bfd0a
AL
644// ---------------------------------------------------------------------
645/* */
8e06abb2 646unsigned long FileFd::Size()
578bfd0a
AL
647{
648 struct stat Buf;
649 if (fstat(iFd,&Buf) != 0)
650 return _error->Errno("fstat","Unable to determine the file size");
651 return Buf.st_size;
652}
653 /*}}}*/
8e06abb2 654// FileFd::Close - Close the file if the close flag is set /*{{{*/
578bfd0a
AL
655// ---------------------------------------------------------------------
656/* */
8e06abb2 657bool FileFd::Close()
578bfd0a
AL
658{
659 bool Res = true;
660 if ((Flags & AutoClose) == AutoClose)
1164783d 661 if (iFd >= 0 && close(iFd) != 0)
b2e465d6 662 Res &= _error->Errno("close",_("Problem closing the file"));
1164783d
AL
663 iFd = -1;
664
578bfd0a
AL
665 if ((Flags & Fail) == Fail && (Flags & DelOnFail) == DelOnFail &&
666 FileName.empty() == false)
667 if (unlink(FileName.c_str()) != 0)
b2e465d6 668 Res &= _error->WarningE("unlnk",_("Problem unlinking the file"));
578bfd0a
AL
669 return Res;
670}
671 /*}}}*/
b2e465d6
AL
672// FileFd::Sync - Sync the file /*{{{*/
673// ---------------------------------------------------------------------
674/* */
675bool FileFd::Sync()
676{
677#ifdef _POSIX_SYNCHRONIZED_IO
678 if (fsync(iFd) != 0)
679 return _error->Errno("sync",_("Problem syncing the file"));
680#endif
681 return true;
682}
683 /*}}}*/