16f7ce929ca0598b10580cc08f3f3c0768f72c4b
[ntk/apt.git] / apt-pkg / contrib / fileutl.cc
1 // -*- mode: cpp; mode: fold -*-
2 // Description /*{{{*/
3 // $Id: fileutl.cc,v 1.42 2002/09/14 05:29:22 jgg Exp $
4 /* ######################################################################
5
6 File Utilities
7
8 CopyFile - Buffered copy of a single file
9 GetLock - dpkg compatible lock file manipulation (fcntl)
10
11 Most of this source is placed in the Public Domain, do with it what
12 you will
13 It was originally written by Jason Gunthorpe <jgg@debian.org>.
14
15 The exception is RunScripts() it is under the GPLv2
16
17 ##################################################################### */
18 /*}}}*/
19 // Include Files /*{{{*/
20 #include <apt-pkg/fileutl.h>
21 #include <apt-pkg/strutl.h>
22 #include <apt-pkg/error.h>
23 #include <apt-pkg/sptr.h>
24 #include <apt-pkg/configuration.h>
25
26 #include <apti18n.h>
27
28 #include <cstdlib>
29 #include <cstring>
30
31 #include <iostream>
32 #include <unistd.h>
33 #include <fcntl.h>
34 #include <sys/stat.h>
35 #include <sys/types.h>
36 #include <sys/time.h>
37 #include <sys/wait.h>
38 #include <dirent.h>
39 #include <signal.h>
40 #include <errno.h>
41 #include <set>
42 #include <algorithm>
43 /*}}}*/
44
45 using namespace std;
46
47 // RunScripts - Run a set of scripts from a configuration subtree /*{{{*/
48 // ---------------------------------------------------------------------
49 /* */
50 bool RunScripts(const char *Cnf)
51 {
52 Configuration::Item const *Opts = _config->Tree(Cnf);
53 if (Opts == 0 || Opts->Child == 0)
54 return true;
55 Opts = Opts->Child;
56
57 // Fork for running the system calls
58 pid_t Child = ExecFork();
59
60 // This is the child
61 if (Child == 0)
62 {
63 if (chdir("/tmp/") != 0)
64 _exit(100);
65
66 unsigned int Count = 1;
67 for (; Opts != 0; Opts = Opts->Next, Count++)
68 {
69 if (Opts->Value.empty() == true)
70 continue;
71
72 if (system(Opts->Value.c_str()) != 0)
73 _exit(100+Count);
74 }
75 _exit(0);
76 }
77
78 // Wait for the child
79 int Status = 0;
80 while (waitpid(Child,&Status,0) != Child)
81 {
82 if (errno == EINTR)
83 continue;
84 return _error->Errno("waitpid","Couldn't wait for subprocess");
85 }
86
87 // Restore sig int/quit
88 signal(SIGQUIT,SIG_DFL);
89 signal(SIGINT,SIG_DFL);
90
91 // Check for an error code.
92 if (WIFEXITED(Status) == 0 || WEXITSTATUS(Status) != 0)
93 {
94 unsigned int Count = WEXITSTATUS(Status);
95 if (Count > 100)
96 {
97 Count -= 100;
98 for (; Opts != 0 && Count != 1; Opts = Opts->Next, Count--);
99 _error->Error("Problem executing scripts %s '%s'",Cnf,Opts->Value.c_str());
100 }
101
102 return _error->Error("Sub-process returned an error code");
103 }
104
105 return true;
106 }
107 /*}}}*/
108
109 // CopyFile - Buffered copy of a file /*{{{*/
110 // ---------------------------------------------------------------------
111 /* The caller is expected to set things so that failure causes erasure */
112 bool CopyFile(FileFd &From,FileFd &To)
113 {
114 if (From.IsOpen() == false || To.IsOpen() == false)
115 return false;
116
117 // Buffered copy between fds
118 SPtrArray<unsigned char> Buf = new unsigned char[64000];
119 unsigned long Size = From.Size();
120 while (Size != 0)
121 {
122 unsigned long ToRead = Size;
123 if (Size > 64000)
124 ToRead = 64000;
125
126 if (From.Read(Buf,ToRead) == false ||
127 To.Write(Buf,ToRead) == false)
128 return false;
129
130 Size -= ToRead;
131 }
132
133 return true;
134 }
135 /*}}}*/
136 // GetLock - Gets a lock file /*{{{*/
137 // ---------------------------------------------------------------------
138 /* This will create an empty file of the given name and lock it. Once this
139 is done all other calls to GetLock in any other process will fail with
140 -1. The return result is the fd of the file, the call should call
141 close at some time. */
142 int GetLock(string File,bool Errors)
143 {
144 // GetLock() is used in aptitude on directories with public-write access
145 // Use O_NOFOLLOW here to prevent symlink traversal attacks
146 int FD = open(File.c_str(),O_RDWR | O_CREAT | O_NOFOLLOW,0640);
147 if (FD < 0)
148 {
149 // Read only .. cant have locking problems there.
150 if (errno == EROFS)
151 {
152 _error->Warning(_("Not using locking for read only lock file %s"),File.c_str());
153 return dup(0); // Need something for the caller to close
154 }
155
156 if (Errors == true)
157 _error->Errno("open",_("Could not open lock file %s"),File.c_str());
158
159 // Feh.. We do this to distinguish the lock vs open case..
160 errno = EPERM;
161 return -1;
162 }
163 SetCloseExec(FD,true);
164
165 // Aquire a write lock
166 struct flock fl;
167 fl.l_type = F_WRLCK;
168 fl.l_whence = SEEK_SET;
169 fl.l_start = 0;
170 fl.l_len = 0;
171 if (fcntl(FD,F_SETLK,&fl) == -1)
172 {
173 if (errno == ENOLCK)
174 {
175 _error->Warning(_("Not using locking for nfs mounted lock file %s"),File.c_str());
176 return dup(0); // Need something for the caller to close
177 }
178 if (Errors == true)
179 _error->Errno("open",_("Could not get lock %s"),File.c_str());
180
181 int Tmp = errno;
182 close(FD);
183 errno = Tmp;
184 return -1;
185 }
186
187 return FD;
188 }
189 /*}}}*/
190 // FileExists - Check if a file exists /*{{{*/
191 // ---------------------------------------------------------------------
192 /* */
193 bool FileExists(string File)
194 {
195 struct stat Buf;
196 if (stat(File.c_str(),&Buf) != 0)
197 return false;
198 return true;
199 }
200 /*}}}*/
201 // DirectoryExists - Check if a directory exists and is really one /*{{{*/
202 // ---------------------------------------------------------------------
203 /* */
204 bool DirectoryExists(string const &Path)
205 {
206 struct stat Buf;
207 if (stat(Path.c_str(),&Buf) != 0)
208 return false;
209 return ((Buf.st_mode & S_IFDIR) != 0);
210 }
211 /*}}}*/
212 // CreateDirectory - poor man's mkdir -p guarded by a parent directory /*{{{*/
213 // ---------------------------------------------------------------------
214 /* This method will create all directories needed for path in good old
215 mkdir -p style but refuses to do this if Parent is not a prefix of
216 this Path. Example: /var/cache/ and /var/cache/apt/archives are given,
217 so it will create apt/archives if /var/cache exists - on the other
218 hand if the parent is /var/lib the creation will fail as this path
219 is not a parent of the path to be generated. */
220 bool CreateDirectory(string const &Parent, string const &Path)
221 {
222 if (Parent.empty() == true || Path.empty() == true)
223 return false;
224
225 if (DirectoryExists(Path) == true)
226 return true;
227
228 if (DirectoryExists(Parent) == false)
229 return false;
230
231 // we are not going to create directories "into the blue"
232 if (Path.find(Parent, 0) != 0)
233 return false;
234
235 vector<string> const dirs = VectorizeString(Path.substr(Parent.size()), '/');
236 string progress = Parent;
237 for (vector<string>::const_iterator d = dirs.begin(); d != dirs.end(); ++d)
238 {
239 if (d->empty() == true)
240 continue;
241
242 progress.append("/").append(*d);
243 if (DirectoryExists(progress) == true)
244 continue;
245
246 if (mkdir(progress.c_str(), 0755) != 0)
247 return false;
248 }
249 return true;
250 }
251 /*}}}*/
252 // GetListOfFilesInDir - returns a vector of files in the given dir /*{{{*/
253 // ---------------------------------------------------------------------
254 /* If an extension is given only files with this extension are included
255 in the returned vector, otherwise every "normal" file is included. */
256 std::vector<string> GetListOfFilesInDir(string const &Dir, string const &Ext,
257 bool const &SortList, bool const &AllowNoExt)
258 {
259 std::vector<string> ext;
260 ext.reserve(2);
261 if (Ext.empty() == false)
262 ext.push_back(Ext);
263 if (AllowNoExt == true && ext.empty() == false)
264 ext.push_back("");
265 return GetListOfFilesInDir(Dir, ext, SortList);
266 }
267 std::vector<string> GetListOfFilesInDir(string const &Dir, std::vector<string> const &Ext,
268 bool const &SortList)
269 {
270 // Attention debuggers: need to be set with the environment config file!
271 bool const Debug = _config->FindB("Debug::GetListOfFilesInDir", false);
272 if (Debug == true)
273 {
274 std::clog << "Accept in " << Dir << " only files with the following " << Ext.size() << " extensions:" << std::endl;
275 if (Ext.empty() == true)
276 std::clog << "\tNO extension" << std::endl;
277 else
278 for (std::vector<string>::const_iterator e = Ext.begin();
279 e != Ext.end(); ++e)
280 std::clog << '\t' << (e->empty() == true ? "NO" : *e) << " extension" << std::endl;
281 }
282
283 std::vector<string> List;
284 DIR *D = opendir(Dir.c_str());
285 if (D == 0)
286 {
287 _error->Errno("opendir",_("Unable to read %s"),Dir.c_str());
288 return List;
289 }
290
291 for (struct dirent *Ent = readdir(D); Ent != 0; Ent = readdir(D))
292 {
293 // skip "hidden" files
294 if (Ent->d_name[0] == '.')
295 continue;
296
297 // check for accepted extension:
298 // no extension given -> periods are bad as hell!
299 // extensions given -> "" extension allows no extension
300 if (Ext.empty() == false)
301 {
302 string d_ext = flExtension(Ent->d_name);
303 if (d_ext == Ent->d_name) // no extension
304 {
305 if (std::find(Ext.begin(), Ext.end(), "") == Ext.end())
306 {
307 if (Debug == true)
308 std::clog << "Bad file: " << Ent->d_name << " → no extension" << std::endl;
309 continue;
310 }
311 }
312 else if (std::find(Ext.begin(), Ext.end(), d_ext) == Ext.end())
313 {
314 if (Debug == true)
315 std::clog << "Bad file: " << Ent->d_name << " → bad extension »" << flExtension(Ent->d_name) << "«" << std::endl;
316 continue;
317 }
318 }
319
320 // Skip bad filenames ala run-parts
321 const char *C = Ent->d_name;
322 for (; *C != 0; ++C)
323 if (isalpha(*C) == 0 && isdigit(*C) == 0
324 && *C != '_' && *C != '-') {
325 // no required extension -> dot is a bad character
326 if (*C == '.' && Ext.empty() == false)
327 continue;
328 break;
329 }
330
331 // we don't reach the end of the name -> bad character included
332 if (*C != 0)
333 {
334 if (Debug == true)
335 std::clog << "Bad file: " << Ent->d_name << " → bad character »"
336 << *C << "« in filename (period allowed: " << (Ext.empty() ? "no" : "yes") << ")" << std::endl;
337 continue;
338 }
339
340 // skip filenames which end with a period. These are never valid
341 if (*(C - 1) == '.')
342 {
343 if (Debug == true)
344 std::clog << "Bad file: " << Ent->d_name << " → Period as last character" << std::endl;
345 continue;
346 }
347
348 // Make sure it is a file and not something else
349 string const File = flCombine(Dir,Ent->d_name);
350 struct stat St;
351 if (stat(File.c_str(),&St) != 0 || S_ISREG(St.st_mode) == 0)
352 {
353 if (Debug == true)
354 std::clog << "Bad file: " << Ent->d_name << " → stat says not a good file" << std::endl;
355 continue;
356 }
357
358 if (Debug == true)
359 std::clog << "Accept file: " << Ent->d_name << " in " << Dir << std::endl;
360 List.push_back(File);
361 }
362 closedir(D);
363
364 if (SortList == true)
365 std::sort(List.begin(),List.end());
366 return List;
367 }
368 /*}}}*/
369 // SafeGetCWD - This is a safer getcwd that returns a dynamic string /*{{{*/
370 // ---------------------------------------------------------------------
371 /* We return / on failure. */
372 string SafeGetCWD()
373 {
374 // Stash the current dir.
375 char S[300];
376 S[0] = 0;
377 if (getcwd(S,sizeof(S)-2) == 0)
378 return "/";
379 unsigned int Len = strlen(S);
380 S[Len] = '/';
381 S[Len+1] = 0;
382 return S;
383 }
384 /*}}}*/
385 // flNotDir - Strip the directory from the filename /*{{{*/
386 // ---------------------------------------------------------------------
387 /* */
388 string flNotDir(string File)
389 {
390 string::size_type Res = File.rfind('/');
391 if (Res == string::npos)
392 return File;
393 Res++;
394 return string(File,Res,Res - File.length());
395 }
396 /*}}}*/
397 // flNotFile - Strip the file from the directory name /*{{{*/
398 // ---------------------------------------------------------------------
399 /* Result ends in a / */
400 string flNotFile(string File)
401 {
402 string::size_type Res = File.rfind('/');
403 if (Res == string::npos)
404 return "./";
405 Res++;
406 return string(File,0,Res);
407 }
408 /*}}}*/
409 // flExtension - Return the extension for the file /*{{{*/
410 // ---------------------------------------------------------------------
411 /* */
412 string flExtension(string File)
413 {
414 string::size_type Res = File.rfind('.');
415 if (Res == string::npos)
416 return File;
417 Res++;
418 return string(File,Res,Res - File.length());
419 }
420 /*}}}*/
421 // flNoLink - If file is a symlink then deref it /*{{{*/
422 // ---------------------------------------------------------------------
423 /* If the name is not a link then the returned path is the input. */
424 string flNoLink(string File)
425 {
426 struct stat St;
427 if (lstat(File.c_str(),&St) != 0 || S_ISLNK(St.st_mode) == 0)
428 return File;
429 if (stat(File.c_str(),&St) != 0)
430 return File;
431
432 /* Loop resolving the link. There is no need to limit the number of
433 loops because the stat call above ensures that the symlink is not
434 circular */
435 char Buffer[1024];
436 string NFile = File;
437 while (1)
438 {
439 // Read the link
440 int Res;
441 if ((Res = readlink(NFile.c_str(),Buffer,sizeof(Buffer))) <= 0 ||
442 (unsigned)Res >= sizeof(Buffer))
443 return File;
444
445 // Append or replace the previous path
446 Buffer[Res] = 0;
447 if (Buffer[0] == '/')
448 NFile = Buffer;
449 else
450 NFile = flNotFile(NFile) + Buffer;
451
452 // See if we are done
453 if (lstat(NFile.c_str(),&St) != 0)
454 return File;
455 if (S_ISLNK(St.st_mode) == 0)
456 return NFile;
457 }
458 }
459 /*}}}*/
460 // flCombine - Combine a file and a directory /*{{{*/
461 // ---------------------------------------------------------------------
462 /* If the file is an absolute path then it is just returned, otherwise
463 the directory is pre-pended to it. */
464 string flCombine(string Dir,string File)
465 {
466 if (File.empty() == true)
467 return string();
468
469 if (File[0] == '/' || Dir.empty() == true)
470 return File;
471 if (File.length() >= 2 && File[0] == '.' && File[1] == '/')
472 return File;
473 if (Dir[Dir.length()-1] == '/')
474 return Dir + File;
475 return Dir + '/' + File;
476 }
477 /*}}}*/
478 // SetCloseExec - Set the close on exec flag /*{{{*/
479 // ---------------------------------------------------------------------
480 /* */
481 void SetCloseExec(int Fd,bool Close)
482 {
483 if (fcntl(Fd,F_SETFD,(Close == false)?0:FD_CLOEXEC) != 0)
484 {
485 cerr << "FATAL -> Could not set close on exec " << strerror(errno) << endl;
486 exit(100);
487 }
488 }
489 /*}}}*/
490 // SetNonBlock - Set the nonblocking flag /*{{{*/
491 // ---------------------------------------------------------------------
492 /* */
493 void SetNonBlock(int Fd,bool Block)
494 {
495 int Flags = fcntl(Fd,F_GETFL) & (~O_NONBLOCK);
496 if (fcntl(Fd,F_SETFL,Flags | ((Block == false)?0:O_NONBLOCK)) != 0)
497 {
498 cerr << "FATAL -> Could not set non-blocking flag " << strerror(errno) << endl;
499 exit(100);
500 }
501 }
502 /*}}}*/
503 // WaitFd - Wait for a FD to become readable /*{{{*/
504 // ---------------------------------------------------------------------
505 /* This waits for a FD to become readable using select. It is useful for
506 applications making use of non-blocking sockets. The timeout is
507 in seconds. */
508 bool WaitFd(int Fd,bool write,unsigned long timeout)
509 {
510 fd_set Set;
511 struct timeval tv;
512 FD_ZERO(&Set);
513 FD_SET(Fd,&Set);
514 tv.tv_sec = timeout;
515 tv.tv_usec = 0;
516 if (write == true)
517 {
518 int Res;
519 do
520 {
521 Res = select(Fd+1,0,&Set,0,(timeout != 0?&tv:0));
522 }
523 while (Res < 0 && errno == EINTR);
524
525 if (Res <= 0)
526 return false;
527 }
528 else
529 {
530 int Res;
531 do
532 {
533 Res = select(Fd+1,&Set,0,0,(timeout != 0?&tv:0));
534 }
535 while (Res < 0 && errno == EINTR);
536
537 if (Res <= 0)
538 return false;
539 }
540
541 return true;
542 }
543 /*}}}*/
544 // ExecFork - Magical fork that sanitizes the context before execing /*{{{*/
545 // ---------------------------------------------------------------------
546 /* This is used if you want to cleanse the environment for the forked
547 child, it fixes up the important signals and nukes all of the fds,
548 otherwise acts like normal fork. */
549 pid_t ExecFork()
550 {
551 // Fork off the process
552 pid_t Process = fork();
553 if (Process < 0)
554 {
555 cerr << "FATAL -> Failed to fork." << endl;
556 exit(100);
557 }
558
559 // Spawn the subprocess
560 if (Process == 0)
561 {
562 // Setup the signals
563 signal(SIGPIPE,SIG_DFL);
564 signal(SIGQUIT,SIG_DFL);
565 signal(SIGINT,SIG_DFL);
566 signal(SIGWINCH,SIG_DFL);
567 signal(SIGCONT,SIG_DFL);
568 signal(SIGTSTP,SIG_DFL);
569
570 set<int> KeepFDs;
571 Configuration::Item const *Opts = _config->Tree("APT::Keep-Fds");
572 if (Opts != 0 && Opts->Child != 0)
573 {
574 Opts = Opts->Child;
575 for (; Opts != 0; Opts = Opts->Next)
576 {
577 if (Opts->Value.empty() == true)
578 continue;
579 int fd = atoi(Opts->Value.c_str());
580 KeepFDs.insert(fd);
581 }
582 }
583
584 // Close all of our FDs - just in case
585 for (int K = 3; K != 40; K++)
586 {
587 if(KeepFDs.find(K) == KeepFDs.end())
588 fcntl(K,F_SETFD,FD_CLOEXEC);
589 }
590 }
591
592 return Process;
593 }
594 /*}}}*/
595 // ExecWait - Fancy waitpid /*{{{*/
596 // ---------------------------------------------------------------------
597 /* Waits for the given sub process. If Reap is set then no errors are
598 generated. Otherwise a failed subprocess will generate a proper descriptive
599 message */
600 bool ExecWait(pid_t Pid,const char *Name,bool Reap)
601 {
602 if (Pid <= 1)
603 return true;
604
605 // Wait and collect the error code
606 int Status;
607 while (waitpid(Pid,&Status,0) != Pid)
608 {
609 if (errno == EINTR)
610 continue;
611
612 if (Reap == true)
613 return false;
614
615 return _error->Error(_("Waited for %s but it wasn't there"),Name);
616 }
617
618
619 // Check for an error code.
620 if (WIFEXITED(Status) == 0 || WEXITSTATUS(Status) != 0)
621 {
622 if (Reap == true)
623 return false;
624 if (WIFSIGNALED(Status) != 0)
625 {
626 if( WTERMSIG(Status) == SIGSEGV)
627 return _error->Error(_("Sub-process %s received a segmentation fault."),Name);
628 else
629 return _error->Error(_("Sub-process %s received signal %u."),Name, WTERMSIG(Status));
630 }
631
632 if (WIFEXITED(Status) != 0)
633 return _error->Error(_("Sub-process %s returned an error code (%u)"),Name,WEXITSTATUS(Status));
634
635 return _error->Error(_("Sub-process %s exited unexpectedly"),Name);
636 }
637
638 return true;
639 }
640 /*}}}*/
641
642 // FileFd::Open - Open a file /*{{{*/
643 // ---------------------------------------------------------------------
644 /* The most commonly used open mode combinations are given with Mode */
645 bool FileFd::Open(string FileName,OpenMode Mode, unsigned long Perms)
646 {
647 Close();
648 Flags = AutoClose;
649 switch (Mode)
650 {
651 case ReadOnly:
652 iFd = open(FileName.c_str(),O_RDONLY);
653 break;
654
655 case WriteEmpty:
656 {
657 struct stat Buf;
658 if (lstat(FileName.c_str(),&Buf) == 0 && S_ISLNK(Buf.st_mode))
659 unlink(FileName.c_str());
660 iFd = open(FileName.c_str(),O_RDWR | O_CREAT | O_TRUNC,Perms);
661 break;
662 }
663
664 case WriteExists:
665 iFd = open(FileName.c_str(),O_RDWR);
666 break;
667
668 case WriteAny:
669 iFd = open(FileName.c_str(),O_RDWR | O_CREAT,Perms);
670 break;
671
672 case WriteTemp:
673 unlink(FileName.c_str());
674 iFd = open(FileName.c_str(),O_RDWR | O_CREAT | O_EXCL,Perms);
675 break;
676 }
677
678 if (iFd < 0)
679 return _error->Errno("open",_("Could not open file %s"),FileName.c_str());
680
681 this->FileName = FileName;
682 SetCloseExec(iFd,true);
683 return true;
684 }
685 /*}}}*/
686 // FileFd::~File - Closes the file /*{{{*/
687 // ---------------------------------------------------------------------
688 /* If the proper modes are selected then we close the Fd and possibly
689 unlink the file on error. */
690 FileFd::~FileFd()
691 {
692 Close();
693 }
694 /*}}}*/
695 // FileFd::Read - Read a bit of the file /*{{{*/
696 // ---------------------------------------------------------------------
697 /* We are carefull to handle interruption by a signal while reading
698 gracefully. */
699 bool FileFd::Read(void *To,unsigned long Size,unsigned long *Actual)
700 {
701 int Res;
702 errno = 0;
703 if (Actual != 0)
704 *Actual = 0;
705
706 do
707 {
708 Res = read(iFd,To,Size);
709 if (Res < 0 && errno == EINTR)
710 continue;
711 if (Res < 0)
712 {
713 Flags |= Fail;
714 return _error->Errno("read",_("Read error"));
715 }
716
717 To = (char *)To + Res;
718 Size -= Res;
719 if (Actual != 0)
720 *Actual += Res;
721 }
722 while (Res > 0 && Size > 0);
723
724 if (Size == 0)
725 return true;
726
727 // Eof handling
728 if (Actual != 0)
729 {
730 Flags |= HitEof;
731 return true;
732 }
733
734 Flags |= Fail;
735 return _error->Error(_("read, still have %lu to read but none left"),Size);
736 }
737 /*}}}*/
738 // FileFd::Write - Write to the file /*{{{*/
739 // ---------------------------------------------------------------------
740 /* */
741 bool FileFd::Write(const void *From,unsigned long Size)
742 {
743 int Res;
744 errno = 0;
745 do
746 {
747 Res = write(iFd,From,Size);
748 if (Res < 0 && errno == EINTR)
749 continue;
750 if (Res < 0)
751 {
752 Flags |= Fail;
753 return _error->Errno("write",_("Write error"));
754 }
755
756 From = (char *)From + Res;
757 Size -= Res;
758 }
759 while (Res > 0 && Size > 0);
760
761 if (Size == 0)
762 return true;
763
764 Flags |= Fail;
765 return _error->Error(_("write, still have %lu to write but couldn't"),Size);
766 }
767 /*}}}*/
768 // FileFd::Seek - Seek in the file /*{{{*/
769 // ---------------------------------------------------------------------
770 /* */
771 bool FileFd::Seek(unsigned long To)
772 {
773 if (lseek(iFd,To,SEEK_SET) != (signed)To)
774 {
775 Flags |= Fail;
776 return _error->Error("Unable to seek to %lu",To);
777 }
778
779 return true;
780 }
781 /*}}}*/
782 // FileFd::Skip - Seek in the file /*{{{*/
783 // ---------------------------------------------------------------------
784 /* */
785 bool FileFd::Skip(unsigned long Over)
786 {
787 if (lseek(iFd,Over,SEEK_CUR) < 0)
788 {
789 Flags |= Fail;
790 return _error->Error("Unable to seek ahead %lu",Over);
791 }
792
793 return true;
794 }
795 /*}}}*/
796 // FileFd::Truncate - Truncate the file /*{{{*/
797 // ---------------------------------------------------------------------
798 /* */
799 bool FileFd::Truncate(unsigned long To)
800 {
801 if (ftruncate(iFd,To) != 0)
802 {
803 Flags |= Fail;
804 return _error->Error("Unable to truncate to %lu",To);
805 }
806
807 return true;
808 }
809 /*}}}*/
810 // FileFd::Tell - Current seek position /*{{{*/
811 // ---------------------------------------------------------------------
812 /* */
813 unsigned long FileFd::Tell()
814 {
815 off_t Res = lseek(iFd,0,SEEK_CUR);
816 if (Res == (off_t)-1)
817 _error->Errno("lseek","Failed to determine the current file position");
818 return Res;
819 }
820 /*}}}*/
821 // FileFd::Size - Return the size of the file /*{{{*/
822 // ---------------------------------------------------------------------
823 /* */
824 unsigned long FileFd::Size()
825 {
826 struct stat Buf;
827 if (fstat(iFd,&Buf) != 0)
828 return _error->Errno("fstat","Unable to determine the file size");
829 return Buf.st_size;
830 }
831 /*}}}*/
832 // FileFd::Close - Close the file if the close flag is set /*{{{*/
833 // ---------------------------------------------------------------------
834 /* */
835 bool FileFd::Close()
836 {
837 bool Res = true;
838 if ((Flags & AutoClose) == AutoClose)
839 if (iFd >= 0 && close(iFd) != 0)
840 Res &= _error->Errno("close",_("Problem closing the file"));
841 iFd = -1;
842
843 if ((Flags & Fail) == Fail && (Flags & DelOnFail) == DelOnFail &&
844 FileName.empty() == false)
845 if (unlink(FileName.c_str()) != 0)
846 Res &= _error->WarningE("unlnk",_("Problem unlinking the file"));
847 return Res;
848 }
849 /*}}}*/
850 // FileFd::Sync - Sync the file /*{{{*/
851 // ---------------------------------------------------------------------
852 /* */
853 bool FileFd::Sync()
854 {
855 #ifdef _POSIX_SYNCHRONIZED_IO
856 if (fsync(iFd) != 0)
857 return _error->Errno("sync",_("Problem syncing the file"));
858 #endif
859 return true;
860 }
861 /*}}}*/