]> git.saurik.com Git - apt.git/blame - apt-pkg/contrib/fileutl.cc
Daniel Jacobowitz's gcc 2.95 C++ patch
[apt.git] / apt-pkg / contrib / fileutl.cc
CommitLineData
578bfd0a
AL
1// -*- mode: cpp; mode: fold -*-
2// Description /*{{{*/
727f18af 3// $Id: fileutl.cc,v 1.29 1999/07/20 05:53:33 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
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 /*{{{*/
6c139d6e 17#ifdef __GNUG__
094a497d 18#pragma implementation "apt-pkg/fileutl.h"
6c139d6e 19#endif
094a497d
AL
20#include <apt-pkg/fileutl.h>
21#include <apt-pkg/error.h>
578bfd0a
AL
22
23#include <unistd.h>
24#include <sys/stat.h>
25#include <sys/fcntl.h>
26#include <sys/types.h>
cc2313b7 27#include <sys/time.h>
54676e1a 28#include <signal.h>
65a1e968 29#include <errno.h>
578bfd0a
AL
30 /*}}}*/
31
32// CopyFile - Buffered copy of a file /*{{{*/
33// ---------------------------------------------------------------------
34/* The caller is expected to set things so that failure causes erasure */
8b89e57f 35bool CopyFile(FileFd &From,FileFd &To)
578bfd0a
AL
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];
b0db36b1
AL
42 unsigned long Size = From.Size();
43 while (Size != 0)
578bfd0a 44 {
b0db36b1
AL
45 unsigned long ToRead = Size;
46 if (Size > 64000)
47 ToRead = 64000;
48
4a6d5862 49 if (From.Read(Buf,ToRead) == false ||
b0db36b1 50 To.Write(Buf,ToRead) == false)
578bfd0a
AL
51 {
52 delete [] Buf;
53 return false;
54 }
b0db36b1
AL
55
56 Size -= ToRead;
578bfd0a
AL
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;
c71bc556
AL
81 fl.l_type = F_WRLCK;
82 fl.l_whence = SEEK_SET;
83 fl.l_start = 0;
84 fl.l_len = 0;
578bfd0a
AL
85 if (fcntl(FD,F_SETLK,&fl) == -1)
86 {
d89df07a
AL
87 if (errno == ENOLCK)
88 {
f44344b3 89 _error->Warning("Not using locking for nfs mounted lock file %s",File.c_str());
d89df07a
AL
90 return true;
91 }
578bfd0a
AL
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;
7f25bdff 120 if (getcwd(S,sizeof(S)-2) == 0)
578bfd0a 121 return "/";
7f25bdff
AL
122 unsigned int Len = strlen(S);
123 S[Len] = '/';
124 S[Len+1] = 0;
578bfd0a
AL
125 return S;
126}
127 /*}}}*/
8ce4327b
AL
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 /*}}}*/
d38b7b3d
AL
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 /*}}}*/
3b5421b4
AL
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{
0a8a80e5
AL
169 int Flags = fcntl(Fd,F_GETFL) & (~O_NONBLOCK);
170 if (fcntl(Fd,F_SETFL,Flags | ((Block == false)?0:O_NONBLOCK)) != 0)
3b5421b4
AL
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
6d5dd02a
AL
180 applications making use of non-blocking sockets. The timeout is
181 in seconds. */
1084d58a 182bool WaitFd(int Fd,bool write,unsigned long timeout)
3b5421b4
AL
183{
184 fd_set Set;
cc2313b7 185 struct timeval tv;
3b5421b4
AL
186 FD_ZERO(&Set);
187 FD_SET(Fd,&Set);
6d5dd02a
AL
188 tv.tv_sec = timeout;
189 tv.tv_usec = 0;
1084d58a 190 if (write == true)
b0db36b1
AL
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;
1084d58a
AL
201 }
202 else
203 {
b0db36b1
AL
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;
cc2313b7 213 }
1084d58a 214
3b5421b4
AL
215 return true;
216}
217 /*}}}*/
54676e1a
AL
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 /*}}}*/
578bfd0a 252
13d87e2e 253// FileFd::Open - Open a file /*{{{*/
578bfd0a
AL
254// ---------------------------------------------------------------------
255/* The most commonly used open mode combinations are given with Mode */
13d87e2e 256bool FileFd::Open(string FileName,OpenMode Mode, unsigned long Perms)
578bfd0a 257{
13d87e2e 258 Close();
1164783d 259 Flags = AutoClose;
578bfd0a
AL
260 switch (Mode)
261 {
262 case ReadOnly:
263 iFd = open(FileName.c_str(),O_RDONLY);
264 break;
265
266 case WriteEmpty:
50b513a1
AL
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 }
578bfd0a
AL
274
275 case WriteExists:
276 iFd = open(FileName.c_str(),O_RDWR);
277 break;
0a8e3465
AL
278
279 case WriteAny:
280 iFd = open(FileName.c_str(),O_RDWR | O_CREAT,Perms);
d38b7b3d 281 break;
578bfd0a
AL
282 }
283
284 if (iFd < 0)
13d87e2e
AL
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;
578bfd0a
AL
290}
291 /*}}}*/
8e06abb2 292// FileFd::~File - Closes the file /*{{{*/
578bfd0a
AL
293// ---------------------------------------------------------------------
294/* If the proper modes are selected then we close the Fd and possibly
295 unlink the file on error. */
8e06abb2 296FileFd::~FileFd()
578bfd0a
AL
297{
298 Close();
299}
300 /*}}}*/
8e06abb2 301// FileFd::Read - Read a bit of the file /*{{{*/
578bfd0a 302// ---------------------------------------------------------------------
b0db36b1
AL
303/* We are carefull to handle interruption by a signal while reading
304 gracefully. */
8e06abb2 305bool FileFd::Read(void *To,unsigned long Size)
578bfd0a 306{
b0db36b1
AL
307 int Res;
308 errno = 0;
309 do
578bfd0a 310 {
b0db36b1
AL
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 }
578bfd0a 319
b0db36b1
AL
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);
578bfd0a
AL
330}
331 /*}}}*/
8e06abb2 332// FileFd::Write - Write to the file /*{{{*/
578bfd0a
AL
333// ---------------------------------------------------------------------
334/* */
a05599f1 335bool FileFd::Write(const void *From,unsigned long Size)
578bfd0a 336{
b0db36b1
AL
337 int Res;
338 errno = 0;
339 do
578bfd0a 340 {
b0db36b1
AL
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;
578bfd0a 352 }
b0db36b1 353 while (Res > 0 && Size > 0);
578bfd0a 354
b0db36b1
AL
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);
578bfd0a
AL
360}
361 /*}}}*/
8e06abb2 362// FileFd::Seek - Seek in the file /*{{{*/
578bfd0a
AL
363// ---------------------------------------------------------------------
364/* */
8e06abb2 365bool FileFd::Seek(unsigned long To)
578bfd0a
AL
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
727f18af
AL
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
6d5dd02a
AL
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
578bfd0a
AL
401 return true;
402}
403 /*}}}*/
7f25bdff
AL
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 /*}}}*/
8e06abb2 415// FileFd::Size - Return the size of the file /*{{{*/
578bfd0a
AL
416// ---------------------------------------------------------------------
417/* */
8e06abb2 418unsigned long FileFd::Size()
578bfd0a
AL
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 /*}}}*/
8e06abb2 426// FileFd::Close - Close the file if the close flag is set /*{{{*/
578bfd0a
AL
427// ---------------------------------------------------------------------
428/* */
8e06abb2 429bool FileFd::Close()
578bfd0a
AL
430{
431 bool Res = true;
432 if ((Flags & AutoClose) == AutoClose)
1164783d 433 if (iFd >= 0 && close(iFd) != 0)
578bfd0a 434 Res &= _error->Errno("close","Problem closing the file");
1164783d
AL
435 iFd = -1;
436
578bfd0a
AL
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 /*}}}*/