Added compile and unpack support to apt-get
[ntk/apt.git] / apt-pkg / contrib / fileutl.cc
CommitLineData
578bfd0a
AL
1// -*- mode: cpp; mode: fold -*-
2// Description /*{{{*/
f44344b3 3// $Id: fileutl.cc,v 1.26 1999/03/21 07:24:14 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>
65a1e968 28#include <errno.h>
578bfd0a
AL
29 /*}}}*/
30
31// CopyFile - Buffered copy of a file /*{{{*/
32// ---------------------------------------------------------------------
33/* The caller is expected to set things so that failure causes erasure */
8b89e57f 34bool CopyFile(FileFd &From,FileFd &To)
578bfd0a
AL
35{
36 if (From.IsOpen() == false || To.IsOpen() == false)
37 return false;
38
39 // Buffered copy between fds
40 unsigned char *Buf = new unsigned char[64000];
b0db36b1
AL
41 unsigned long Size = From.Size();
42 while (Size != 0)
578bfd0a 43 {
b0db36b1
AL
44 unsigned long ToRead = Size;
45 if (Size > 64000)
46 ToRead = 64000;
47
4a6d5862 48 if (From.Read(Buf,ToRead) == false ||
b0db36b1 49 To.Write(Buf,ToRead) == false)
578bfd0a
AL
50 {
51 delete [] Buf;
52 return false;
53 }
b0db36b1
AL
54
55 Size -= ToRead;
578bfd0a
AL
56 }
57
58 delete [] Buf;
59 return true;
60}
61 /*}}}*/
62// GetLock - Gets a lock file /*{{{*/
63// ---------------------------------------------------------------------
64/* This will create an empty file of the given name and lock it. Once this
65 is done all other calls to GetLock in any other process will fail with
66 -1. The return result is the fd of the file, the call should call
67 close at some time. */
68int GetLock(string File,bool Errors)
69{
70 int FD = open(File.c_str(),O_RDWR | O_CREAT | O_TRUNC,0640);
71 if (FD < 0)
72 {
73 if (Errors == true)
74 _error->Errno("open","Could not open lock file %s",File.c_str());
75 return -1;
76 }
77
78 // Aquire a write lock
79 struct flock fl;
c71bc556
AL
80 fl.l_type = F_WRLCK;
81 fl.l_whence = SEEK_SET;
82 fl.l_start = 0;
83 fl.l_len = 0;
578bfd0a
AL
84 if (fcntl(FD,F_SETLK,&fl) == -1)
85 {
d89df07a
AL
86 if (errno == ENOLCK)
87 {
f44344b3 88 _error->Warning("Not using locking for nfs mounted lock file %s",File.c_str());
d89df07a
AL
89 return true;
90 }
578bfd0a
AL
91 if (Errors == true)
92 _error->Errno("open","Could not get lock %s",File.c_str());
93 close(FD);
94 return -1;
95 }
96
97 return FD;
98}
99 /*}}}*/
100// FileExists - Check if a file exists /*{{{*/
101// ---------------------------------------------------------------------
102/* */
103bool FileExists(string File)
104{
105 struct stat Buf;
106 if (stat(File.c_str(),&Buf) != 0)
107 return false;
108 return true;
109}
110 /*}}}*/
111// SafeGetCWD - This is a safer getcwd that returns a dynamic string /*{{{*/
112// ---------------------------------------------------------------------
113/* We return / on failure. */
114string SafeGetCWD()
115{
116 // Stash the current dir.
117 char S[300];
118 S[0] = 0;
7f25bdff 119 if (getcwd(S,sizeof(S)-2) == 0)
578bfd0a 120 return "/";
7f25bdff
AL
121 unsigned int Len = strlen(S);
122 S[Len] = '/';
123 S[Len+1] = 0;
578bfd0a
AL
124 return S;
125}
126 /*}}}*/
8ce4327b
AL
127// flNotDir - Strip the directory from the filename /*{{{*/
128// ---------------------------------------------------------------------
129/* */
130string flNotDir(string File)
131{
132 string::size_type Res = File.rfind('/');
133 if (Res == string::npos)
134 return File;
135 Res++;
136 return string(File,Res,Res - File.length());
137}
138 /*}}}*/
d38b7b3d
AL
139// flNotFile - Strip the file from the directory name /*{{{*/
140// ---------------------------------------------------------------------
141/* */
142string flNotFile(string File)
143{
144 string::size_type Res = File.rfind('/');
145 if (Res == string::npos)
146 return File;
147 Res++;
148 return string(File,0,Res);
149}
150 /*}}}*/
3b5421b4
AL
151// SetCloseExec - Set the close on exec flag /*{{{*/
152// ---------------------------------------------------------------------
153/* */
154void SetCloseExec(int Fd,bool Close)
155{
156 if (fcntl(Fd,F_SETFD,(Close == false)?0:FD_CLOEXEC) != 0)
157 {
158 cerr << "FATAL -> Could not set close on exec " << strerror(errno) << endl;
159 exit(100);
160 }
161}
162 /*}}}*/
163// SetNonBlock - Set the nonblocking flag /*{{{*/
164// ---------------------------------------------------------------------
165/* */
166void SetNonBlock(int Fd,bool Block)
167{
0a8a80e5
AL
168 int Flags = fcntl(Fd,F_GETFL) & (~O_NONBLOCK);
169 if (fcntl(Fd,F_SETFL,Flags | ((Block == false)?0:O_NONBLOCK)) != 0)
3b5421b4
AL
170 {
171 cerr << "FATAL -> Could not set non-blocking flag " << strerror(errno) << endl;
172 exit(100);
173 }
174}
175 /*}}}*/
176// WaitFd - Wait for a FD to become readable /*{{{*/
177// ---------------------------------------------------------------------
178/* This waits for a FD to become readable using select. It is usefull for
6d5dd02a
AL
179 applications making use of non-blocking sockets. The timeout is
180 in seconds. */
1084d58a 181bool WaitFd(int Fd,bool write,unsigned long timeout)
3b5421b4
AL
182{
183 fd_set Set;
cc2313b7 184 struct timeval tv;
3b5421b4
AL
185 FD_ZERO(&Set);
186 FD_SET(Fd,&Set);
6d5dd02a
AL
187 tv.tv_sec = timeout;
188 tv.tv_usec = 0;
1084d58a 189 if (write == true)
b0db36b1
AL
190 {
191 int Res;
192 do
193 {
194 Res = select(Fd+1,0,&Set,0,(timeout != 0?&tv:0));
195 }
196 while (Res < 0 && errno == EINTR);
197
198 if (Res <= 0)
199 return false;
1084d58a
AL
200 }
201 else
202 {
b0db36b1
AL
203 int Res;
204 do
205 {
206 Res = select(Fd+1,&Set,0,0,(timeout != 0?&tv:0));
207 }
208 while (Res < 0 && errno == EINTR);
209
210 if (Res <= 0)
211 return false;
cc2313b7 212 }
1084d58a 213
3b5421b4
AL
214 return true;
215}
216 /*}}}*/
578bfd0a 217
8e06abb2 218// FileFd::FileFd - Open a file /*{{{*/
578bfd0a
AL
219// ---------------------------------------------------------------------
220/* The most commonly used open mode combinations are given with Mode */
8e06abb2 221FileFd::FileFd(string FileName,OpenMode Mode, unsigned long Perms)
578bfd0a 222{
1164783d 223 Flags = AutoClose;
578bfd0a
AL
224 switch (Mode)
225 {
226 case ReadOnly:
227 iFd = open(FileName.c_str(),O_RDONLY);
228 break;
229
230 case WriteEmpty:
50b513a1
AL
231 {
232 struct stat Buf;
233 if (stat(FileName.c_str(),&Buf) == 0 && S_ISLNK(Buf.st_mode))
234 unlink(FileName.c_str());
235 iFd = open(FileName.c_str(),O_RDWR | O_CREAT | O_TRUNC,Perms);
236 break;
237 }
578bfd0a
AL
238
239 case WriteExists:
240 iFd = open(FileName.c_str(),O_RDWR);
241 break;
0a8e3465
AL
242
243 case WriteAny:
244 iFd = open(FileName.c_str(),O_RDWR | O_CREAT,Perms);
d38b7b3d 245 break;
578bfd0a
AL
246 }
247
248 if (iFd < 0)
249 _error->Errno("open","Could not open file %s",FileName.c_str());
250 else
4b4fd143 251 {
578bfd0a 252 this->FileName = FileName;
4b4fd143
AL
253 SetCloseExec(iFd,true);
254 }
578bfd0a
AL
255}
256 /*}}}*/
8e06abb2 257// FileFd::~File - Closes the file /*{{{*/
578bfd0a
AL
258// ---------------------------------------------------------------------
259/* If the proper modes are selected then we close the Fd and possibly
260 unlink the file on error. */
8e06abb2 261FileFd::~FileFd()
578bfd0a
AL
262{
263 Close();
264}
265 /*}}}*/
8e06abb2 266// FileFd::Read - Read a bit of the file /*{{{*/
578bfd0a 267// ---------------------------------------------------------------------
b0db36b1
AL
268/* We are carefull to handle interruption by a signal while reading
269 gracefully. */
8e06abb2 270bool FileFd::Read(void *To,unsigned long Size)
578bfd0a 271{
b0db36b1
AL
272 int Res;
273 errno = 0;
274 do
578bfd0a 275 {
b0db36b1
AL
276 Res = read(iFd,To,Size);
277 if (Res < 0 && errno == EINTR)
278 continue;
279 if (Res < 0)
280 {
281 Flags |= Fail;
282 return _error->Errno("read","Read error");
283 }
578bfd0a 284
b0db36b1
AL
285 To = (char *)To + Res;
286 Size -= Res;
287 }
288 while (Res > 0 && Size > 0);
289
290 if (Size == 0)
291 return true;
292
293 Flags |= Fail;
294 return _error->Error("read, still have %u to read but none left",Size);
578bfd0a
AL
295}
296 /*}}}*/
8e06abb2 297// FileFd::Write - Write to the file /*{{{*/
578bfd0a
AL
298// ---------------------------------------------------------------------
299/* */
a05599f1 300bool FileFd::Write(const void *From,unsigned long Size)
578bfd0a 301{
b0db36b1
AL
302 int Res;
303 errno = 0;
304 do
578bfd0a 305 {
b0db36b1
AL
306 Res = write(iFd,From,Size);
307 if (Res < 0 && errno == EINTR)
308 continue;
309 if (Res < 0)
310 {
311 Flags |= Fail;
312 return _error->Errno("write","Write error");
313 }
314
315 From = (char *)From + Res;
316 Size -= Res;
578bfd0a 317 }
b0db36b1 318 while (Res > 0 && Size > 0);
578bfd0a 319
b0db36b1
AL
320 if (Size == 0)
321 return true;
322
323 Flags |= Fail;
324 return _error->Error("write, still have %u to write but couldn't",Size);
578bfd0a
AL
325}
326 /*}}}*/
8e06abb2 327// FileFd::Seek - Seek in the file /*{{{*/
578bfd0a
AL
328// ---------------------------------------------------------------------
329/* */
8e06abb2 330bool FileFd::Seek(unsigned long To)
578bfd0a
AL
331{
332 if (lseek(iFd,To,SEEK_SET) != (signed)To)
333 {
334 Flags |= Fail;
335 return _error->Error("Unable to seek to %u",To);
336 }
337
6d5dd02a
AL
338 return true;
339}
340 /*}}}*/
341// FileFd::Truncate - Truncate the file /*{{{*/
342// ---------------------------------------------------------------------
343/* */
344bool FileFd::Truncate(unsigned long To)
345{
346 if (ftruncate(iFd,To) != 0)
347 {
348 Flags |= Fail;
349 return _error->Error("Unable to truncate to %u",To);
350 }
351
578bfd0a
AL
352 return true;
353}
354 /*}}}*/
7f25bdff
AL
355// FileFd::Tell - Current seek position /*{{{*/
356// ---------------------------------------------------------------------
357/* */
358unsigned long FileFd::Tell()
359{
360 off_t Res = lseek(iFd,0,SEEK_CUR);
361 if (Res == (off_t)-1)
362 _error->Errno("lseek","Failed to determine the current file position");
363 return Res;
364}
365 /*}}}*/
8e06abb2 366// FileFd::Size - Return the size of the file /*{{{*/
578bfd0a
AL
367// ---------------------------------------------------------------------
368/* */
8e06abb2 369unsigned long FileFd::Size()
578bfd0a
AL
370{
371 struct stat Buf;
372 if (fstat(iFd,&Buf) != 0)
373 return _error->Errno("fstat","Unable to determine the file size");
374 return Buf.st_size;
375}
376 /*}}}*/
8e06abb2 377// FileFd::Close - Close the file if the close flag is set /*{{{*/
578bfd0a
AL
378// ---------------------------------------------------------------------
379/* */
8e06abb2 380bool FileFd::Close()
578bfd0a
AL
381{
382 bool Res = true;
383 if ((Flags & AutoClose) == AutoClose)
1164783d 384 if (iFd >= 0 && close(iFd) != 0)
578bfd0a 385 Res &= _error->Errno("close","Problem closing the file");
1164783d
AL
386 iFd = -1;
387
578bfd0a
AL
388 if ((Flags & Fail) == Fail && (Flags & DelOnFail) == DelOnFail &&
389 FileName.empty() == false)
390 if (unlink(FileName.c_str()) != 0)
391 Res &= _error->Warning("unlnk","Problem unlinking the file");
392 return Res;
393}
394 /*}}}*/