]> git.saurik.com Git - apt.git/blame - apt-pkg/contrib/fileutl.cc
Error code
[apt.git] / apt-pkg / contrib / fileutl.cc
CommitLineData
578bfd0a
AL
1// -*- mode: cpp; mode: fold -*-
2// Description /*{{{*/
54676e1a 3// $Id: fileutl.cc,v 1.27 1999/04/20 05:02:09 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
8e06abb2 253// FileFd::FileFd - Open a file /*{{{*/
578bfd0a
AL
254// ---------------------------------------------------------------------
255/* The most commonly used open mode combinations are given with Mode */
8e06abb2 256FileFd::FileFd(string FileName,OpenMode Mode, unsigned long Perms)
578bfd0a 257{
1164783d 258 Flags = AutoClose;
578bfd0a
AL
259 switch (Mode)
260 {
261 case ReadOnly:
262 iFd = open(FileName.c_str(),O_RDONLY);
263 break;
264
265 case WriteEmpty:
50b513a1
AL
266 {
267 struct stat Buf;
268 if (stat(FileName.c_str(),&Buf) == 0 && S_ISLNK(Buf.st_mode))
269 unlink(FileName.c_str());
270 iFd = open(FileName.c_str(),O_RDWR | O_CREAT | O_TRUNC,Perms);
271 break;
272 }
578bfd0a
AL
273
274 case WriteExists:
275 iFd = open(FileName.c_str(),O_RDWR);
276 break;
0a8e3465
AL
277
278 case WriteAny:
279 iFd = open(FileName.c_str(),O_RDWR | O_CREAT,Perms);
d38b7b3d 280 break;
578bfd0a
AL
281 }
282
283 if (iFd < 0)
284 _error->Errno("open","Could not open file %s",FileName.c_str());
285 else
4b4fd143 286 {
578bfd0a 287 this->FileName = FileName;
4b4fd143
AL
288 SetCloseExec(iFd,true);
289 }
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
6d5dd02a
AL
373 return true;
374}
375 /*}}}*/
376// FileFd::Truncate - Truncate the file /*{{{*/
377// ---------------------------------------------------------------------
378/* */
379bool FileFd::Truncate(unsigned long To)
380{
381 if (ftruncate(iFd,To) != 0)
382 {
383 Flags |= Fail;
384 return _error->Error("Unable to truncate to %u",To);
385 }
386
578bfd0a
AL
387 return true;
388}
389 /*}}}*/
7f25bdff
AL
390// FileFd::Tell - Current seek position /*{{{*/
391// ---------------------------------------------------------------------
392/* */
393unsigned long FileFd::Tell()
394{
395 off_t Res = lseek(iFd,0,SEEK_CUR);
396 if (Res == (off_t)-1)
397 _error->Errno("lseek","Failed to determine the current file position");
398 return Res;
399}
400 /*}}}*/
8e06abb2 401// FileFd::Size - Return the size of the file /*{{{*/
578bfd0a
AL
402// ---------------------------------------------------------------------
403/* */
8e06abb2 404unsigned long FileFd::Size()
578bfd0a
AL
405{
406 struct stat Buf;
407 if (fstat(iFd,&Buf) != 0)
408 return _error->Errno("fstat","Unable to determine the file size");
409 return Buf.st_size;
410}
411 /*}}}*/
8e06abb2 412// FileFd::Close - Close the file if the close flag is set /*{{{*/
578bfd0a
AL
413// ---------------------------------------------------------------------
414/* */
8e06abb2 415bool FileFd::Close()
578bfd0a
AL
416{
417 bool Res = true;
418 if ((Flags & AutoClose) == AutoClose)
1164783d 419 if (iFd >= 0 && close(iFd) != 0)
578bfd0a 420 Res &= _error->Errno("close","Problem closing the file");
1164783d
AL
421 iFd = -1;
422
578bfd0a
AL
423 if ((Flags & Fail) == Fail && (Flags & DelOnFail) == DelOnFail &&
424 FileName.empty() == false)
425 if (unlink(FileName.c_str()) != 0)
426 Res &= _error->Warning("unlnk","Problem unlinking the file");
427 return Res;
428}
429 /*}}}*/