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