]> git.saurik.com Git - apt.git/blame_incremental - apt-pkg/contrib/fileutl.cc
Daniel Jacobowitz's gcc 2.95 C++ patch
[apt.git] / apt-pkg / contrib / fileutl.cc
... / ...
CommitLineData
1// -*- mode: cpp; mode: fold -*-
2// Description /*{{{*/
3// $Id: fileutl.cc,v 1.29 1999/07/20 05:53:33 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 This source is placed in the Public Domain, do with it what you will
12 It was originally written by Jason Gunthorpe.
13
14 ##################################################################### */
15 /*}}}*/
16// Include Files /*{{{*/
17#ifdef __GNUG__
18#pragma implementation "apt-pkg/fileutl.h"
19#endif
20#include <apt-pkg/fileutl.h>
21#include <apt-pkg/error.h>
22
23#include <unistd.h>
24#include <sys/stat.h>
25#include <sys/fcntl.h>
26#include <sys/types.h>
27#include <sys/time.h>
28#include <signal.h>
29#include <errno.h>
30 /*}}}*/
31
32// CopyFile - Buffered copy of a file /*{{{*/
33// ---------------------------------------------------------------------
34/* The caller is expected to set things so that failure causes erasure */
35bool CopyFile(FileFd &From,FileFd &To)
36{
37 if (From.IsOpen() == false || To.IsOpen() == false)
38 return false;
39
40 // Buffered copy between fds
41 unsigned char *Buf = new unsigned char[64000];
42 unsigned long Size = From.Size();
43 while (Size != 0)
44 {
45 unsigned long ToRead = Size;
46 if (Size > 64000)
47 ToRead = 64000;
48
49 if (From.Read(Buf,ToRead) == false ||
50 To.Write(Buf,ToRead) == false)
51 {
52 delete [] Buf;
53 return false;
54 }
55
56 Size -= ToRead;
57 }
58
59 delete [] Buf;
60 return true;
61}
62 /*}}}*/
63// GetLock - Gets a lock file /*{{{*/
64// ---------------------------------------------------------------------
65/* This will create an empty file of the given name and lock it. Once this
66 is done all other calls to GetLock in any other process will fail with
67 -1. The return result is the fd of the file, the call should call
68 close at some time. */
69int GetLock(string File,bool Errors)
70{
71 int FD = open(File.c_str(),O_RDWR | O_CREAT | O_TRUNC,0640);
72 if (FD < 0)
73 {
74 if (Errors == true)
75 _error->Errno("open","Could not open lock file %s",File.c_str());
76 return -1;
77 }
78
79 // Aquire a write lock
80 struct flock fl;
81 fl.l_type = F_WRLCK;
82 fl.l_whence = SEEK_SET;
83 fl.l_start = 0;
84 fl.l_len = 0;
85 if (fcntl(FD,F_SETLK,&fl) == -1)
86 {
87 if (errno == ENOLCK)
88 {
89 _error->Warning("Not using locking for nfs mounted lock file %s",File.c_str());
90 return true;
91 }
92 if (Errors == true)
93 _error->Errno("open","Could not get lock %s",File.c_str());
94 close(FD);
95 return -1;
96 }
97
98 return FD;
99}
100 /*}}}*/
101// FileExists - Check if a file exists /*{{{*/
102// ---------------------------------------------------------------------
103/* */
104bool FileExists(string File)
105{
106 struct stat Buf;
107 if (stat(File.c_str(),&Buf) != 0)
108 return false;
109 return true;
110}
111 /*}}}*/
112// SafeGetCWD - This is a safer getcwd that returns a dynamic string /*{{{*/
113// ---------------------------------------------------------------------
114/* We return / on failure. */
115string SafeGetCWD()
116{
117 // Stash the current dir.
118 char S[300];
119 S[0] = 0;
120 if (getcwd(S,sizeof(S)-2) == 0)
121 return "/";
122 unsigned int Len = strlen(S);
123 S[Len] = '/';
124 S[Len+1] = 0;
125 return S;
126}
127 /*}}}*/
128// flNotDir - Strip the directory from the filename /*{{{*/
129// ---------------------------------------------------------------------
130/* */
131string flNotDir(string File)
132{
133 string::size_type Res = File.rfind('/');
134 if (Res == string::npos)
135 return File;
136 Res++;
137 return string(File,Res,Res - File.length());
138}
139 /*}}}*/
140// flNotFile - Strip the file from the directory name /*{{{*/
141// ---------------------------------------------------------------------
142/* */
143string flNotFile(string File)
144{
145 string::size_type Res = File.rfind('/');
146 if (Res == string::npos)
147 return File;
148 Res++;
149 return string(File,0,Res);
150}
151 /*}}}*/
152// SetCloseExec - Set the close on exec flag /*{{{*/
153// ---------------------------------------------------------------------
154/* */
155void SetCloseExec(int Fd,bool Close)
156{
157 if (fcntl(Fd,F_SETFD,(Close == false)?0:FD_CLOEXEC) != 0)
158 {
159 cerr << "FATAL -> Could not set close on exec " << strerror(errno) << endl;
160 exit(100);
161 }
162}
163 /*}}}*/
164// SetNonBlock - Set the nonblocking flag /*{{{*/
165// ---------------------------------------------------------------------
166/* */
167void SetNonBlock(int Fd,bool Block)
168{
169 int Flags = fcntl(Fd,F_GETFL) & (~O_NONBLOCK);
170 if (fcntl(Fd,F_SETFL,Flags | ((Block == false)?0:O_NONBLOCK)) != 0)
171 {
172 cerr << "FATAL -> Could not set non-blocking flag " << strerror(errno) << endl;
173 exit(100);
174 }
175}
176 /*}}}*/
177// WaitFd - Wait for a FD to become readable /*{{{*/
178// ---------------------------------------------------------------------
179/* This waits for a FD to become readable using select. It is usefull for
180 applications making use of non-blocking sockets. The timeout is
181 in seconds. */
182bool WaitFd(int Fd,bool write,unsigned long timeout)
183{
184 fd_set Set;
185 struct timeval tv;
186 FD_ZERO(&Set);
187 FD_SET(Fd,&Set);
188 tv.tv_sec = timeout;
189 tv.tv_usec = 0;
190 if (write == true)
191 {
192 int Res;
193 do
194 {
195 Res = select(Fd+1,0,&Set,0,(timeout != 0?&tv:0));
196 }
197 while (Res < 0 && errno == EINTR);
198
199 if (Res <= 0)
200 return false;
201 }
202 else
203 {
204 int Res;
205 do
206 {
207 Res = select(Fd+1,&Set,0,0,(timeout != 0?&tv:0));
208 }
209 while (Res < 0 && errno == EINTR);
210
211 if (Res <= 0)
212 return false;
213 }
214
215 return true;
216}
217 /*}}}*/
218// ExecFork - Magical fork that sanitizes the context before execing /*{{{*/
219// ---------------------------------------------------------------------
220/* This is used if you want to cleanse the environment for the forked
221 child, it fixes up the important signals and nukes all of the fds,
222 otherwise acts like normal fork. */
223int ExecFork()
224{
225 // Fork off the process
226 pid_t Process = fork();
227 if (Process < 0)
228 {
229 cerr << "FATAL -> Failed to fork." << endl;
230 exit(100);
231 }
232
233 // Spawn the subprocess
234 if (Process == 0)
235 {
236 // Setup the signals
237 signal(SIGPIPE,SIG_DFL);
238 signal(SIGQUIT,SIG_DFL);
239 signal(SIGINT,SIG_DFL);
240 signal(SIGWINCH,SIG_DFL);
241 signal(SIGCONT,SIG_DFL);
242 signal(SIGTSTP,SIG_DFL);
243
244 // Close all of our FDs - just in case
245 for (int K = 3; K != 40; K++)
246 fcntl(K,F_SETFD,FD_CLOEXEC);
247 }
248
249 return Process;
250}
251 /*}}}*/
252
253// FileFd::Open - Open a file /*{{{*/
254// ---------------------------------------------------------------------
255/* The most commonly used open mode combinations are given with Mode */
256bool FileFd::Open(string FileName,OpenMode Mode, unsigned long Perms)
257{
258 Close();
259 Flags = AutoClose;
260 switch (Mode)
261 {
262 case ReadOnly:
263 iFd = open(FileName.c_str(),O_RDONLY);
264 break;
265
266 case WriteEmpty:
267 {
268 struct stat Buf;
269 if (stat(FileName.c_str(),&Buf) == 0 && S_ISLNK(Buf.st_mode))
270 unlink(FileName.c_str());
271 iFd = open(FileName.c_str(),O_RDWR | O_CREAT | O_TRUNC,Perms);
272 break;
273 }
274
275 case WriteExists:
276 iFd = open(FileName.c_str(),O_RDWR);
277 break;
278
279 case WriteAny:
280 iFd = open(FileName.c_str(),O_RDWR | O_CREAT,Perms);
281 break;
282 }
283
284 if (iFd < 0)
285 return _error->Errno("open","Could not open file %s",FileName.c_str());
286
287 this->FileName = FileName;
288 SetCloseExec(iFd,true);
289 return true;
290}
291 /*}}}*/
292// FileFd::~File - Closes the file /*{{{*/
293// ---------------------------------------------------------------------
294/* If the proper modes are selected then we close the Fd and possibly
295 unlink the file on error. */
296FileFd::~FileFd()
297{
298 Close();
299}
300 /*}}}*/
301// FileFd::Read - Read a bit of the file /*{{{*/
302// ---------------------------------------------------------------------
303/* We are carefull to handle interruption by a signal while reading
304 gracefully. */
305bool FileFd::Read(void *To,unsigned long Size)
306{
307 int Res;
308 errno = 0;
309 do
310 {
311 Res = read(iFd,To,Size);
312 if (Res < 0 && errno == EINTR)
313 continue;
314 if (Res < 0)
315 {
316 Flags |= Fail;
317 return _error->Errno("read","Read error");
318 }
319
320 To = (char *)To + Res;
321 Size -= Res;
322 }
323 while (Res > 0 && Size > 0);
324
325 if (Size == 0)
326 return true;
327
328 Flags |= Fail;
329 return _error->Error("read, still have %u to read but none left",Size);
330}
331 /*}}}*/
332// FileFd::Write - Write to the file /*{{{*/
333// ---------------------------------------------------------------------
334/* */
335bool FileFd::Write(const void *From,unsigned long Size)
336{
337 int Res;
338 errno = 0;
339 do
340 {
341 Res = write(iFd,From,Size);
342 if (Res < 0 && errno == EINTR)
343 continue;
344 if (Res < 0)
345 {
346 Flags |= Fail;
347 return _error->Errno("write","Write error");
348 }
349
350 From = (char *)From + Res;
351 Size -= Res;
352 }
353 while (Res > 0 && Size > 0);
354
355 if (Size == 0)
356 return true;
357
358 Flags |= Fail;
359 return _error->Error("write, still have %u to write but couldn't",Size);
360}
361 /*}}}*/
362// FileFd::Seek - Seek in the file /*{{{*/
363// ---------------------------------------------------------------------
364/* */
365bool FileFd::Seek(unsigned long To)
366{
367 if (lseek(iFd,To,SEEK_SET) != (signed)To)
368 {
369 Flags |= Fail;
370 return _error->Error("Unable to seek to %u",To);
371 }
372
373 return true;
374}
375 /*}}}*/
376// FileFd::Skip - Seek in the file /*{{{*/
377// ---------------------------------------------------------------------
378/* */
379bool FileFd::Skip(unsigned long Over)
380{
381 if (lseek(iFd,Over,SEEK_CUR) < 0)
382 {
383 Flags |= Fail;
384 return _error->Error("Unable to seek ahead %u",Over);
385 }
386
387 return true;
388}
389 /*}}}*/
390// FileFd::Truncate - Truncate the file /*{{{*/
391// ---------------------------------------------------------------------
392/* */
393bool FileFd::Truncate(unsigned long To)
394{
395 if (ftruncate(iFd,To) != 0)
396 {
397 Flags |= Fail;
398 return _error->Error("Unable to truncate to %u",To);
399 }
400
401 return true;
402}
403 /*}}}*/
404// FileFd::Tell - Current seek position /*{{{*/
405// ---------------------------------------------------------------------
406/* */
407unsigned long FileFd::Tell()
408{
409 off_t Res = lseek(iFd,0,SEEK_CUR);
410 if (Res == (off_t)-1)
411 _error->Errno("lseek","Failed to determine the current file position");
412 return Res;
413}
414 /*}}}*/
415// FileFd::Size - Return the size of the file /*{{{*/
416// ---------------------------------------------------------------------
417/* */
418unsigned long FileFd::Size()
419{
420 struct stat Buf;
421 if (fstat(iFd,&Buf) != 0)
422 return _error->Errno("fstat","Unable to determine the file size");
423 return Buf.st_size;
424}
425 /*}}}*/
426// FileFd::Close - Close the file if the close flag is set /*{{{*/
427// ---------------------------------------------------------------------
428/* */
429bool FileFd::Close()
430{
431 bool Res = true;
432 if ((Flags & AutoClose) == AutoClose)
433 if (iFd >= 0 && close(iFd) != 0)
434 Res &= _error->Errno("close","Problem closing the file");
435 iFd = -1;
436
437 if ((Flags & Fail) == Fail && (Flags & DelOnFail) == DelOnFail &&
438 FileName.empty() == false)
439 if (unlink(FileName.c_str()) != 0)
440 Res &= _error->Warning("unlnk","Problem unlinking the file");
441 return Res;
442}
443 /*}}}*/