]>
git.saurik.com Git - apt.git/blob - apt-pkg/contrib/fileutl.cc
1 // -*- mode: cpp; mode: fold -*-
3 // $Id: fileutl.cc,v 1.30 1999/07/26 17:46:08 jgg Exp $
4 /* ######################################################################
8 CopyFile - Buffered copy of a single file
9 GetLock - dpkg compatible lock file manipulation (fcntl)
11 This source is placed in the Public Domain, do with it what you will
12 It was originally written by Jason Gunthorpe.
14 ##################################################################### */
16 // Include Files /*{{{*/
18 #pragma implementation "apt-pkg/fileutl.h"
20 #include <apt-pkg/fileutl.h>
21 #include <apt-pkg/error.h>
25 #include <sys/fcntl.h>
26 #include <sys/types.h>
33 // CopyFile - Buffered copy of a file /*{{{*/
34 // ---------------------------------------------------------------------
35 /* The caller is expected to set things so that failure causes erasure */
36 bool CopyFile(FileFd
&From
,FileFd
&To
)
38 if (From
.IsOpen() == false || To
.IsOpen() == false)
41 // Buffered copy between fds
42 unsigned char *Buf
= new unsigned char[64000];
43 unsigned long Size
= From
.Size();
46 unsigned long ToRead
= Size
;
50 if (From
.Read(Buf
,ToRead
) == false ||
51 To
.Write(Buf
,ToRead
) == false)
64 // GetLock - Gets a lock file /*{{{*/
65 // ---------------------------------------------------------------------
66 /* This will create an empty file of the given name and lock it. Once this
67 is done all other calls to GetLock in any other process will fail with
68 -1. The return result is the fd of the file, the call should call
69 close at some time. */
70 int GetLock(string File
,bool Errors
)
72 int FD
= open(File
.c_str(),O_RDWR
| O_CREAT
| O_TRUNC
,0640);
76 _error
->Errno("open","Could not open lock file %s",File
.c_str());
80 // Aquire a write lock
83 fl
.l_whence
= SEEK_SET
;
86 if (fcntl(FD
,F_SETLK
,&fl
) == -1)
90 _error
->Warning("Not using locking for nfs mounted lock file %s",File
.c_str());
94 _error
->Errno("open","Could not get lock %s",File
.c_str());
102 // FileExists - Check if a file exists /*{{{*/
103 // ---------------------------------------------------------------------
105 bool FileExists(string File
)
108 if (stat(File
.c_str(),&Buf
) != 0)
113 // SafeGetCWD - This is a safer getcwd that returns a dynamic string /*{{{*/
114 // ---------------------------------------------------------------------
115 /* We return / on failure. */
118 // Stash the current dir.
121 if (getcwd(S
,sizeof(S
)-2) == 0)
123 unsigned int Len
= strlen(S
);
129 // flNotDir - Strip the directory from the filename /*{{{*/
130 // ---------------------------------------------------------------------
132 string
flNotDir(string File
)
134 string::size_type Res
= File
.rfind('/');
135 if (Res
== string::npos
)
138 return string(File
,Res
,Res
- File
.length());
141 // flNotFile - Strip the file from the directory name /*{{{*/
142 // ---------------------------------------------------------------------
144 string
flNotFile(string File
)
146 string::size_type Res
= File
.rfind('/');
147 if (Res
== string::npos
)
150 return string(File
,0,Res
);
153 // SetCloseExec - Set the close on exec flag /*{{{*/
154 // ---------------------------------------------------------------------
156 void SetCloseExec(int Fd
,bool Close
)
158 if (fcntl(Fd
,F_SETFD
,(Close
== false)?0:FD_CLOEXEC
) != 0)
160 cerr
<< "FATAL -> Could not set close on exec " << strerror(errno
) << endl
;
165 // SetNonBlock - Set the nonblocking flag /*{{{*/
166 // ---------------------------------------------------------------------
168 void SetNonBlock(int Fd
,bool Block
)
170 int Flags
= fcntl(Fd
,F_GETFL
) & (~O_NONBLOCK
);
171 if (fcntl(Fd
,F_SETFL
,Flags
| ((Block
== false)?0:O_NONBLOCK
)) != 0)
173 cerr
<< "FATAL -> Could not set non-blocking flag " << strerror(errno
) << endl
;
178 // WaitFd - Wait for a FD to become readable /*{{{*/
179 // ---------------------------------------------------------------------
180 /* This waits for a FD to become readable using select. It is usefull for
181 applications making use of non-blocking sockets. The timeout is
183 bool WaitFd(int Fd
,bool write
,unsigned long timeout
)
196 Res
= select(Fd
+1,0,&Set
,0,(timeout
!= 0?&tv
:0));
198 while (Res
< 0 && errno
== EINTR
);
208 Res
= select(Fd
+1,&Set
,0,0,(timeout
!= 0?&tv
:0));
210 while (Res
< 0 && errno
== EINTR
);
219 // ExecFork - Magical fork that sanitizes the context before execing /*{{{*/
220 // ---------------------------------------------------------------------
221 /* This is used if you want to cleanse the environment for the forked
222 child, it fixes up the important signals and nukes all of the fds,
223 otherwise acts like normal fork. */
226 // Fork off the process
227 pid_t Process
= fork();
230 cerr
<< "FATAL -> Failed to fork." << endl
;
234 // Spawn the subprocess
238 signal(SIGPIPE
,SIG_DFL
);
239 signal(SIGQUIT
,SIG_DFL
);
240 signal(SIGINT
,SIG_DFL
);
241 signal(SIGWINCH
,SIG_DFL
);
242 signal(SIGCONT
,SIG_DFL
);
243 signal(SIGTSTP
,SIG_DFL
);
245 // Close all of our FDs - just in case
246 for (int K
= 3; K
!= 40; K
++)
247 fcntl(K
,F_SETFD
,FD_CLOEXEC
);
253 // ExecWait - Fancy waitpid /*{{{*/
254 // ---------------------------------------------------------------------
255 /* Waits for the given sub process. If Reap is set the no errors are
256 generated. Otherwise a failed subprocess will generate a proper descriptive
258 bool ExecWait(int Pid
,const char *Name
,bool Reap
)
263 // Wait and collect the error code
265 while (waitpid(Pid
,&Status
,0) != Pid
)
273 return _error
->Error("Waited, for %s but it wasn't there",Name
);
277 // Check for an error code.
278 if (WIFEXITED(Status
) == 0 || WEXITSTATUS(Status
) != 0)
282 if (WIFSIGNALED(Status
) != 0 && WTERMSIG(Status
) == SIGSEGV
)
283 return _error
->Error("Sub-process %s recieved a segmentation fault.",Name
);
285 if (WIFEXITED(Status
) != 0)
286 return _error
->Error("Sub-process %s returned an error code (%u)",Name
,WEXITSTATUS(Status
));
288 return _error
->Error("Sub-process %s exited unexpectedly",Name
);
295 // FileFd::Open - Open a file /*{{{*/
296 // ---------------------------------------------------------------------
297 /* The most commonly used open mode combinations are given with Mode */
298 bool FileFd::Open(string FileName
,OpenMode Mode
, unsigned long Perms
)
305 iFd
= open(FileName
.c_str(),O_RDONLY
);
311 if (stat(FileName
.c_str(),&Buf
) == 0 && S_ISLNK(Buf
.st_mode
))
312 unlink(FileName
.c_str());
313 iFd
= open(FileName
.c_str(),O_RDWR
| O_CREAT
| O_TRUNC
,Perms
);
318 iFd
= open(FileName
.c_str(),O_RDWR
);
322 iFd
= open(FileName
.c_str(),O_RDWR
| O_CREAT
,Perms
);
327 return _error
->Errno("open","Could not open file %s",FileName
.c_str());
329 this->FileName
= FileName
;
330 SetCloseExec(iFd
,true);
334 // FileFd::~File - Closes the file /*{{{*/
335 // ---------------------------------------------------------------------
336 /* If the proper modes are selected then we close the Fd and possibly
337 unlink the file on error. */
343 // FileFd::Read - Read a bit of the file /*{{{*/
344 // ---------------------------------------------------------------------
345 /* We are carefull to handle interruption by a signal while reading
347 bool FileFd::Read(void *To
,unsigned long Size
,bool AllowEof
)
353 Res
= read(iFd
,To
,Size
);
354 if (Res
< 0 && errno
== EINTR
)
359 return _error
->Errno("read","Read error");
362 To
= (char *)To
+ Res
;
365 while (Res
> 0 && Size
> 0);
371 if (AllowEof
== true)
378 return _error
->Error("read, still have %u to read but none left",Size
);
381 // FileFd::Write - Write to the file /*{{{*/
382 // ---------------------------------------------------------------------
384 bool FileFd::Write(const void *From
,unsigned long Size
)
390 Res
= write(iFd
,From
,Size
);
391 if (Res
< 0 && errno
== EINTR
)
396 return _error
->Errno("write","Write error");
399 From
= (char *)From
+ Res
;
402 while (Res
> 0 && Size
> 0);
408 return _error
->Error("write, still have %u to write but couldn't",Size
);
411 // FileFd::Seek - Seek in the file /*{{{*/
412 // ---------------------------------------------------------------------
414 bool FileFd::Seek(unsigned long To
)
416 if (lseek(iFd
,To
,SEEK_SET
) != (signed)To
)
419 return _error
->Error("Unable to seek to %u",To
);
425 // FileFd::Skip - Seek in the file /*{{{*/
426 // ---------------------------------------------------------------------
428 bool FileFd::Skip(unsigned long Over
)
430 if (lseek(iFd
,Over
,SEEK_CUR
) < 0)
433 return _error
->Error("Unable to seek ahead %u",Over
);
439 // FileFd::Truncate - Truncate the file /*{{{*/
440 // ---------------------------------------------------------------------
442 bool FileFd::Truncate(unsigned long To
)
444 if (ftruncate(iFd
,To
) != 0)
447 return _error
->Error("Unable to truncate to %u",To
);
453 // FileFd::Tell - Current seek position /*{{{*/
454 // ---------------------------------------------------------------------
456 unsigned long FileFd::Tell()
458 off_t Res
= lseek(iFd
,0,SEEK_CUR
);
459 if (Res
== (off_t
)-1)
460 _error
->Errno("lseek","Failed to determine the current file position");
464 // FileFd::Size - Return the size of the file /*{{{*/
465 // ---------------------------------------------------------------------
467 unsigned long FileFd::Size()
470 if (fstat(iFd
,&Buf
) != 0)
471 return _error
->Errno("fstat","Unable to determine the file size");
475 // FileFd::Close - Close the file if the close flag is set /*{{{*/
476 // ---------------------------------------------------------------------
481 if ((Flags
& AutoClose
) == AutoClose
)
482 if (iFd
>= 0 && close(iFd
) != 0)
483 Res
&= _error
->Errno("close","Problem closing the file");
486 if ((Flags
& Fail
) == Fail
&& (Flags
& DelOnFail
) == DelOnFail
&&
487 FileName
.empty() == false)
488 if (unlink(FileName
.c_str()) != 0)
489 Res
&= _error
->Warning("unlnk","Problem unlinking the file");