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