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