remove the ABI compatible stub for GetListOfFilesInDir
[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>
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. */
b39c1859
MV
204std::vector<string> GetListOfFilesInDir(string const &Dir, string const &Ext,
205 bool const &SortList, bool const &AllowNoExt)
206{
207 std::vector<string> ext;
208 ext.reserve(2);
209 if (Ext.empty() == false)
210 ext.push_back(Ext);
211 if (AllowNoExt == true && ext.empty() == false)
212 ext.push_back("");
213 return GetListOfFilesInDir(Dir, ext, SortList);
214}
215std::vector<string> GetListOfFilesInDir(string const &Dir, std::vector<string> const &Ext,
216 bool const &SortList)
217{
218 // Attention debuggers: need to be set with the environment config file!
219 bool const Debug = _config->FindB("Debug::GetListOfFilesInDir", false);
220 if (Debug == true)
221 {
222 std::clog << "Accept in " << Dir << " only files with the following " << Ext.size() << " extensions:" << std::endl;
223 if (Ext.empty() == true)
224 std::clog << "\tNO extension" << std::endl;
225 else
226 for (std::vector<string>::const_iterator e = Ext.begin();
227 e != Ext.end(); ++e)
228 std::clog << '\t' << (e->empty() == true ? "NO" : *e) << " extension" << std::endl;
229 }
230
46e39c8e
MV
231 std::vector<string> List;
232 DIR *D = opendir(Dir.c_str());
233 if (D == 0)
234 {
235 _error->Errno("opendir",_("Unable to read %s"),Dir.c_str());
236 return List;
237 }
238
239 for (struct dirent *Ent = readdir(D); Ent != 0; Ent = readdir(D))
240 {
b39c1859 241 // skip "hidden" files
46e39c8e
MV
242 if (Ent->d_name[0] == '.')
243 continue;
244
b39c1859
MV
245 // check for accepted extension:
246 // no extension given -> periods are bad as hell!
247 // extensions given -> "" extension allows no extension
248 if (Ext.empty() == false)
249 {
250 string d_ext = flExtension(Ent->d_name);
251 if (d_ext == Ent->d_name) // no extension
252 {
253 if (std::find(Ext.begin(), Ext.end(), "") == Ext.end())
254 {
255 if (Debug == true)
256 std::clog << "Bad file: " << Ent->d_name << " → no extension" << std::endl;
257 continue;
258 }
259 }
260 else if (std::find(Ext.begin(), Ext.end(), d_ext) == Ext.end())
261 {
262 if (Debug == true)
263 std::clog << "Bad file: " << Ent->d_name << " → bad extension »" << flExtension(Ent->d_name) << "«" << std::endl;
264 continue;
265 }
266 }
46e39c8e 267
b39c1859 268 // Skip bad filenames ala run-parts
46e39c8e
MV
269 const char *C = Ent->d_name;
270 for (; *C != 0; ++C)
271 if (isalpha(*C) == 0 && isdigit(*C) == 0
b39c1859
MV
272 && *C != '_' && *C != '-') {
273 // no required extension -> dot is a bad character
274 if (*C == '.' && Ext.empty() == false)
275 continue;
46e39c8e 276 break;
b39c1859 277 }
46e39c8e 278
b39c1859 279 // we don't reach the end of the name -> bad character included
46e39c8e 280 if (*C != 0)
b39c1859
MV
281 {
282 if (Debug == true)
283 std::clog << "Bad file: " << Ent->d_name << " → bad character »"
284 << *C << "« in filename (period allowed: " << (Ext.empty() ? "no" : "yes") << ")" << std::endl;
285 continue;
286 }
287
288 // skip filenames which end with a period. These are never valid
289 if (*(C - 1) == '.')
290 {
291 if (Debug == true)
292 std::clog << "Bad file: " << Ent->d_name << " → Period as last character" << std::endl;
46e39c8e 293 continue;
b39c1859 294 }
46e39c8e
MV
295
296 // Make sure it is a file and not something else
297 string const File = flCombine(Dir,Ent->d_name);
298 struct stat St;
299 if (stat(File.c_str(),&St) != 0 || S_ISREG(St.st_mode) == 0)
b39c1859
MV
300 {
301 if (Debug == true)
302 std::clog << "Bad file: " << Ent->d_name << " → stat says not a good file" << std::endl;
46e39c8e 303 continue;
b39c1859 304 }
46e39c8e 305
b39c1859
MV
306 if (Debug == true)
307 std::clog << "Accept file: " << Ent->d_name << " in " << Dir << std::endl;
46e39c8e
MV
308 List.push_back(File);
309 }
310 closedir(D);
311
312 if (SortList == true)
313 std::sort(List.begin(),List.end());
314 return List;
315}
316 /*}}}*/
578bfd0a
AL
317// SafeGetCWD - This is a safer getcwd that returns a dynamic string /*{{{*/
318// ---------------------------------------------------------------------
319/* We return / on failure. */
320string SafeGetCWD()
321{
322 // Stash the current dir.
323 char S[300];
324 S[0] = 0;
7f25bdff 325 if (getcwd(S,sizeof(S)-2) == 0)
578bfd0a 326 return "/";
7f25bdff
AL
327 unsigned int Len = strlen(S);
328 S[Len] = '/';
329 S[Len+1] = 0;
578bfd0a
AL
330 return S;
331}
332 /*}}}*/
8ce4327b
AL
333// flNotDir - Strip the directory from the filename /*{{{*/
334// ---------------------------------------------------------------------
335/* */
336string flNotDir(string File)
337{
338 string::size_type Res = File.rfind('/');
339 if (Res == string::npos)
340 return File;
341 Res++;
342 return string(File,Res,Res - File.length());
343}
344 /*}}}*/
d38b7b3d
AL
345// flNotFile - Strip the file from the directory name /*{{{*/
346// ---------------------------------------------------------------------
171c45bc 347/* Result ends in a / */
d38b7b3d
AL
348string flNotFile(string File)
349{
350 string::size_type Res = File.rfind('/');
351 if (Res == string::npos)
171c45bc 352 return "./";
d38b7b3d
AL
353 Res++;
354 return string(File,0,Res);
355}
356 /*}}}*/
b2e465d6
AL
357// flExtension - Return the extension for the file /*{{{*/
358// ---------------------------------------------------------------------
359/* */
360string flExtension(string File)
361{
362 string::size_type Res = File.rfind('.');
363 if (Res == string::npos)
364 return File;
365 Res++;
366 return string(File,Res,Res - File.length());
367}
368 /*}}}*/
421c8d10
AL
369// flNoLink - If file is a symlink then deref it /*{{{*/
370// ---------------------------------------------------------------------
371/* If the name is not a link then the returned path is the input. */
372string flNoLink(string File)
373{
374 struct stat St;
375 if (lstat(File.c_str(),&St) != 0 || S_ISLNK(St.st_mode) == 0)
376 return File;
377 if (stat(File.c_str(),&St) != 0)
378 return File;
379
380 /* Loop resolving the link. There is no need to limit the number of
381 loops because the stat call above ensures that the symlink is not
382 circular */
383 char Buffer[1024];
384 string NFile = File;
385 while (1)
386 {
387 // Read the link
388 int Res;
389 if ((Res = readlink(NFile.c_str(),Buffer,sizeof(Buffer))) <= 0 ||
390 (unsigned)Res >= sizeof(Buffer))
391 return File;
392
393 // Append or replace the previous path
394 Buffer[Res] = 0;
395 if (Buffer[0] == '/')
396 NFile = Buffer;
397 else
398 NFile = flNotFile(NFile) + Buffer;
399
400 // See if we are done
401 if (lstat(NFile.c_str(),&St) != 0)
402 return File;
403 if (S_ISLNK(St.st_mode) == 0)
404 return NFile;
405 }
406}
407 /*}}}*/
b2e465d6
AL
408// flCombine - Combine a file and a directory /*{{{*/
409// ---------------------------------------------------------------------
410/* If the file is an absolute path then it is just returned, otherwise
411 the directory is pre-pended to it. */
412string flCombine(string Dir,string File)
413{
414 if (File.empty() == true)
415 return string();
416
417 if (File[0] == '/' || Dir.empty() == true)
418 return File;
419 if (File.length() >= 2 && File[0] == '.' && File[1] == '/')
420 return File;
421 if (Dir[Dir.length()-1] == '/')
422 return Dir + File;
423 return Dir + '/' + File;
424}
425 /*}}}*/
3b5421b4
AL
426// SetCloseExec - Set the close on exec flag /*{{{*/
427// ---------------------------------------------------------------------
428/* */
429void SetCloseExec(int Fd,bool Close)
430{
431 if (fcntl(Fd,F_SETFD,(Close == false)?0:FD_CLOEXEC) != 0)
432 {
433 cerr << "FATAL -> Could not set close on exec " << strerror(errno) << endl;
434 exit(100);
435 }
436}
437 /*}}}*/
438// SetNonBlock - Set the nonblocking flag /*{{{*/
439// ---------------------------------------------------------------------
440/* */
441void SetNonBlock(int Fd,bool Block)
442{
0a8a80e5
AL
443 int Flags = fcntl(Fd,F_GETFL) & (~O_NONBLOCK);
444 if (fcntl(Fd,F_SETFL,Flags | ((Block == false)?0:O_NONBLOCK)) != 0)
3b5421b4
AL
445 {
446 cerr << "FATAL -> Could not set non-blocking flag " << strerror(errno) << endl;
447 exit(100);
448 }
449}
450 /*}}}*/
451// WaitFd - Wait for a FD to become readable /*{{{*/
452// ---------------------------------------------------------------------
b2e465d6 453/* This waits for a FD to become readable using select. It is useful for
6d5dd02a
AL
454 applications making use of non-blocking sockets. The timeout is
455 in seconds. */
1084d58a 456bool WaitFd(int Fd,bool write,unsigned long timeout)
3b5421b4
AL
457{
458 fd_set Set;
cc2313b7 459 struct timeval tv;
3b5421b4
AL
460 FD_ZERO(&Set);
461 FD_SET(Fd,&Set);
6d5dd02a
AL
462 tv.tv_sec = timeout;
463 tv.tv_usec = 0;
1084d58a 464 if (write == true)
b0db36b1
AL
465 {
466 int Res;
467 do
468 {
469 Res = select(Fd+1,0,&Set,0,(timeout != 0?&tv:0));
470 }
471 while (Res < 0 && errno == EINTR);
472
473 if (Res <= 0)
474 return false;
1084d58a
AL
475 }
476 else
477 {
b0db36b1
AL
478 int Res;
479 do
480 {
481 Res = select(Fd+1,&Set,0,0,(timeout != 0?&tv:0));
482 }
483 while (Res < 0 && errno == EINTR);
484
485 if (Res <= 0)
486 return false;
cc2313b7 487 }
1084d58a 488
3b5421b4
AL
489 return true;
490}
491 /*}}}*/
54676e1a
AL
492// ExecFork - Magical fork that sanitizes the context before execing /*{{{*/
493// ---------------------------------------------------------------------
494/* This is used if you want to cleanse the environment for the forked
495 child, it fixes up the important signals and nukes all of the fds,
496 otherwise acts like normal fork. */
75ef8f14 497pid_t ExecFork()
54676e1a
AL
498{
499 // Fork off the process
500 pid_t Process = fork();
501 if (Process < 0)
502 {
503 cerr << "FATAL -> Failed to fork." << endl;
504 exit(100);
505 }
506
507 // Spawn the subprocess
508 if (Process == 0)
509 {
510 // Setup the signals
511 signal(SIGPIPE,SIG_DFL);
512 signal(SIGQUIT,SIG_DFL);
513 signal(SIGINT,SIG_DFL);
514 signal(SIGWINCH,SIG_DFL);
515 signal(SIGCONT,SIG_DFL);
516 signal(SIGTSTP,SIG_DFL);
75ef8f14
MV
517
518 set<int> KeepFDs;
519 Configuration::Item const *Opts = _config->Tree("APT::Keep-Fds");
520 if (Opts != 0 && Opts->Child != 0)
521 {
522 Opts = Opts->Child;
523 for (; Opts != 0; Opts = Opts->Next)
524 {
525 if (Opts->Value.empty() == true)
526 continue;
527 int fd = atoi(Opts->Value.c_str());
528 KeepFDs.insert(fd);
529 }
530 }
531
54676e1a
AL
532 // Close all of our FDs - just in case
533 for (int K = 3; K != 40; K++)
75ef8f14
MV
534 {
535 if(KeepFDs.find(K) == KeepFDs.end())
007dc9e0 536 fcntl(K,F_SETFD,FD_CLOEXEC);
75ef8f14 537 }
54676e1a
AL
538 }
539
540 return Process;
541}
542 /*}}}*/
ddc1d8d0
AL
543// ExecWait - Fancy waitpid /*{{{*/
544// ---------------------------------------------------------------------
2c9a72d1 545/* Waits for the given sub process. If Reap is set then no errors are
ddc1d8d0
AL
546 generated. Otherwise a failed subprocess will generate a proper descriptive
547 message */
3826564e 548bool ExecWait(pid_t Pid,const char *Name,bool Reap)
ddc1d8d0
AL
549{
550 if (Pid <= 1)
551 return true;
552
553 // Wait and collect the error code
554 int Status;
555 while (waitpid(Pid,&Status,0) != Pid)
556 {
557 if (errno == EINTR)
558 continue;
559
560 if (Reap == true)
561 return false;
562
db0db9fe 563 return _error->Error(_("Waited for %s but it wasn't there"),Name);
ddc1d8d0
AL
564 }
565
566
567 // Check for an error code.
568 if (WIFEXITED(Status) == 0 || WEXITSTATUS(Status) != 0)
569 {
570 if (Reap == true)
571 return false;
ab7f4d7c 572 if (WIFSIGNALED(Status) != 0)
40e7fe0e 573 {
ab7f4d7c
MV
574 if( WTERMSIG(Status) == SIGSEGV)
575 return _error->Error(_("Sub-process %s received a segmentation fault."),Name);
576 else
577 return _error->Error(_("Sub-process %s received signal %u."),Name, WTERMSIG(Status));
40e7fe0e 578 }
ddc1d8d0
AL
579
580 if (WIFEXITED(Status) != 0)
b2e465d6 581 return _error->Error(_("Sub-process %s returned an error code (%u)"),Name,WEXITSTATUS(Status));
ddc1d8d0 582
b2e465d6 583 return _error->Error(_("Sub-process %s exited unexpectedly"),Name);
ddc1d8d0
AL
584 }
585
586 return true;
587}
588 /*}}}*/
578bfd0a 589
13d87e2e 590// FileFd::Open - Open a file /*{{{*/
578bfd0a
AL
591// ---------------------------------------------------------------------
592/* The most commonly used open mode combinations are given with Mode */
13d87e2e 593bool FileFd::Open(string FileName,OpenMode Mode, unsigned long Perms)
578bfd0a 594{
13d87e2e 595 Close();
1164783d 596 Flags = AutoClose;
578bfd0a
AL
597 switch (Mode)
598 {
599 case ReadOnly:
600 iFd = open(FileName.c_str(),O_RDONLY);
601 break;
602
603 case WriteEmpty:
50b513a1
AL
604 {
605 struct stat Buf;
459681d3 606 if (lstat(FileName.c_str(),&Buf) == 0 && S_ISLNK(Buf.st_mode))
50b513a1
AL
607 unlink(FileName.c_str());
608 iFd = open(FileName.c_str(),O_RDWR | O_CREAT | O_TRUNC,Perms);
609 break;
610 }
578bfd0a
AL
611
612 case WriteExists:
613 iFd = open(FileName.c_str(),O_RDWR);
614 break;
0a8e3465
AL
615
616 case WriteAny:
617 iFd = open(FileName.c_str(),O_RDWR | O_CREAT,Perms);
d38b7b3d 618 break;
f08fcf34
AL
619
620 case WriteTemp:
4decd43c
AL
621 unlink(FileName.c_str());
622 iFd = open(FileName.c_str(),O_RDWR | O_CREAT | O_EXCL,Perms);
f08fcf34 623 break;
578bfd0a
AL
624 }
625
626 if (iFd < 0)
b2e465d6 627 return _error->Errno("open",_("Could not open file %s"),FileName.c_str());
13d87e2e
AL
628
629 this->FileName = FileName;
630 SetCloseExec(iFd,true);
631 return true;
578bfd0a
AL
632}
633 /*}}}*/
8e06abb2 634// FileFd::~File - Closes the file /*{{{*/
578bfd0a
AL
635// ---------------------------------------------------------------------
636/* If the proper modes are selected then we close the Fd and possibly
637 unlink the file on error. */
8e06abb2 638FileFd::~FileFd()
578bfd0a
AL
639{
640 Close();
641}
642 /*}}}*/
8e06abb2 643// FileFd::Read - Read a bit of the file /*{{{*/
578bfd0a 644// ---------------------------------------------------------------------
b0db36b1
AL
645/* We are carefull to handle interruption by a signal while reading
646 gracefully. */
f604cf55 647bool FileFd::Read(void *To,unsigned long Size,unsigned long *Actual)
578bfd0a 648{
b0db36b1
AL
649 int Res;
650 errno = 0;
f604cf55
AL
651 if (Actual != 0)
652 *Actual = 0;
653
b0db36b1 654 do
578bfd0a 655 {
b0db36b1
AL
656 Res = read(iFd,To,Size);
657 if (Res < 0 && errno == EINTR)
658 continue;
659 if (Res < 0)
660 {
661 Flags |= Fail;
b2e465d6 662 return _error->Errno("read",_("Read error"));
b0db36b1 663 }
578bfd0a 664
b0db36b1
AL
665 To = (char *)To + Res;
666 Size -= Res;
f604cf55
AL
667 if (Actual != 0)
668 *Actual += Res;
b0db36b1
AL
669 }
670 while (Res > 0 && Size > 0);
671
672 if (Size == 0)
673 return true;
674
ddc1d8d0 675 // Eof handling
f604cf55 676 if (Actual != 0)
ddc1d8d0
AL
677 {
678 Flags |= HitEof;
679 return true;
680 }
681
b0db36b1 682 Flags |= Fail;
b2e465d6 683 return _error->Error(_("read, still have %lu to read but none left"),Size);
578bfd0a
AL
684}
685 /*}}}*/
8e06abb2 686// FileFd::Write - Write to the file /*{{{*/
578bfd0a
AL
687// ---------------------------------------------------------------------
688/* */
a05599f1 689bool FileFd::Write(const void *From,unsigned long Size)
578bfd0a 690{
b0db36b1
AL
691 int Res;
692 errno = 0;
693 do
578bfd0a 694 {
b0db36b1
AL
695 Res = write(iFd,From,Size);
696 if (Res < 0 && errno == EINTR)
697 continue;
698 if (Res < 0)
699 {
700 Flags |= Fail;
b2e465d6 701 return _error->Errno("write",_("Write error"));
b0db36b1
AL
702 }
703
704 From = (char *)From + Res;
705 Size -= Res;
578bfd0a 706 }
b0db36b1 707 while (Res > 0 && Size > 0);
578bfd0a 708
b0db36b1
AL
709 if (Size == 0)
710 return true;
711
712 Flags |= Fail;
b2e465d6 713 return _error->Error(_("write, still have %lu to write but couldn't"),Size);
578bfd0a
AL
714}
715 /*}}}*/
8e06abb2 716// FileFd::Seek - Seek in the file /*{{{*/
578bfd0a
AL
717// ---------------------------------------------------------------------
718/* */
8e06abb2 719bool FileFd::Seek(unsigned long To)
578bfd0a
AL
720{
721 if (lseek(iFd,To,SEEK_SET) != (signed)To)
722 {
723 Flags |= Fail;
b2e465d6 724 return _error->Error("Unable to seek to %lu",To);
578bfd0a
AL
725 }
726
727f18af
AL
727 return true;
728}
729 /*}}}*/
730// FileFd::Skip - Seek in the file /*{{{*/
731// ---------------------------------------------------------------------
732/* */
733bool FileFd::Skip(unsigned long Over)
734{
735 if (lseek(iFd,Over,SEEK_CUR) < 0)
736 {
737 Flags |= Fail;
b2e465d6 738 return _error->Error("Unable to seek ahead %lu",Over);
727f18af
AL
739 }
740
6d5dd02a
AL
741 return true;
742}
743 /*}}}*/
744// FileFd::Truncate - Truncate the file /*{{{*/
745// ---------------------------------------------------------------------
746/* */
747bool FileFd::Truncate(unsigned long To)
748{
749 if (ftruncate(iFd,To) != 0)
750 {
751 Flags |= Fail;
b2e465d6 752 return _error->Error("Unable to truncate to %lu",To);
6d5dd02a
AL
753 }
754
578bfd0a
AL
755 return true;
756}
757 /*}}}*/
7f25bdff
AL
758// FileFd::Tell - Current seek position /*{{{*/
759// ---------------------------------------------------------------------
760/* */
761unsigned long FileFd::Tell()
762{
763 off_t Res = lseek(iFd,0,SEEK_CUR);
764 if (Res == (off_t)-1)
765 _error->Errno("lseek","Failed to determine the current file position");
766 return Res;
767}
768 /*}}}*/
8e06abb2 769// FileFd::Size - Return the size of the file /*{{{*/
578bfd0a
AL
770// ---------------------------------------------------------------------
771/* */
8e06abb2 772unsigned long FileFd::Size()
578bfd0a
AL
773{
774 struct stat Buf;
775 if (fstat(iFd,&Buf) != 0)
776 return _error->Errno("fstat","Unable to determine the file size");
777 return Buf.st_size;
778}
779 /*}}}*/
8e06abb2 780// FileFd::Close - Close the file if the close flag is set /*{{{*/
578bfd0a
AL
781// ---------------------------------------------------------------------
782/* */
8e06abb2 783bool FileFd::Close()
578bfd0a
AL
784{
785 bool Res = true;
786 if ((Flags & AutoClose) == AutoClose)
1164783d 787 if (iFd >= 0 && close(iFd) != 0)
b2e465d6 788 Res &= _error->Errno("close",_("Problem closing the file"));
1164783d
AL
789 iFd = -1;
790
578bfd0a
AL
791 if ((Flags & Fail) == Fail && (Flags & DelOnFail) == DelOnFail &&
792 FileName.empty() == false)
793 if (unlink(FileName.c_str()) != 0)
b2e465d6 794 Res &= _error->WarningE("unlnk",_("Problem unlinking the file"));
578bfd0a
AL
795 return Res;
796}
797 /*}}}*/
b2e465d6
AL
798// FileFd::Sync - Sync the file /*{{{*/
799// ---------------------------------------------------------------------
800/* */
801bool FileFd::Sync()
802{
803#ifdef _POSIX_SYNCHRONIZED_IO
804 if (fsync(iFd) != 0)
805 return _error->Errno("sync",_("Problem syncing the file"));
806#endif
807 return true;
808}
809 /*}}}*/