Fixed small virtual package install list glitch
[ntk/apt.git] / apt-pkg / contrib / fileutl.cc
CommitLineData
578bfd0a
AL
1// -*- mode: cpp; mode: fold -*-
2// Description /*{{{*/
c71bc556 3// $Id: fileutl.cc,v 1.18 1999/02/03 23:13:37 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>
27 /*}}}*/
28
29// CopyFile - Buffered copy of a file /*{{{*/
30// ---------------------------------------------------------------------
31/* The caller is expected to set things so that failure causes erasure */
8b89e57f 32bool CopyFile(FileFd &From,FileFd &To)
578bfd0a
AL
33{
34 if (From.IsOpen() == false || To.IsOpen() == false)
35 return false;
36
37 // Buffered copy between fds
38 unsigned char *Buf = new unsigned char[64000];
39 long Size;
40 while ((Size = read(From.Fd(),Buf,64000)) > 0)
41 {
42 if (To.Write(Buf,Size) == false)
43 {
44 delete [] Buf;
45 return false;
46 }
47 }
48
49 delete [] Buf;
50 return true;
51}
52 /*}}}*/
53// GetLock - Gets a lock file /*{{{*/
54// ---------------------------------------------------------------------
55/* This will create an empty file of the given name and lock it. Once this
56 is done all other calls to GetLock in any other process will fail with
57 -1. The return result is the fd of the file, the call should call
58 close at some time. */
59int GetLock(string File,bool Errors)
60{
61 int FD = open(File.c_str(),O_RDWR | O_CREAT | O_TRUNC,0640);
62 if (FD < 0)
63 {
64 if (Errors == true)
65 _error->Errno("open","Could not open lock file %s",File.c_str());
66 return -1;
67 }
68
69 // Aquire a write lock
70 struct flock fl;
c71bc556
AL
71 fl.l_type = F_WRLCK;
72 fl.l_whence = SEEK_SET;
73 fl.l_start = 0;
74 fl.l_len = 0;
578bfd0a
AL
75 if (fcntl(FD,F_SETLK,&fl) == -1)
76 {
77 if (Errors == true)
78 _error->Errno("open","Could not get lock %s",File.c_str());
79 close(FD);
80 return -1;
81 }
82
83 return FD;
84}
85 /*}}}*/
86// FileExists - Check if a file exists /*{{{*/
87// ---------------------------------------------------------------------
88/* */
89bool FileExists(string File)
90{
91 struct stat Buf;
92 if (stat(File.c_str(),&Buf) != 0)
93 return false;
94 return true;
95}
96 /*}}}*/
97// SafeGetCWD - This is a safer getcwd that returns a dynamic string /*{{{*/
98// ---------------------------------------------------------------------
99/* We return / on failure. */
100string SafeGetCWD()
101{
102 // Stash the current dir.
103 char S[300];
104 S[0] = 0;
7f25bdff 105 if (getcwd(S,sizeof(S)-2) == 0)
578bfd0a 106 return "/";
7f25bdff
AL
107 unsigned int Len = strlen(S);
108 S[Len] = '/';
109 S[Len+1] = 0;
578bfd0a
AL
110 return S;
111}
112 /*}}}*/
8ce4327b
AL
113// flNotDir - Strip the directory from the filename /*{{{*/
114// ---------------------------------------------------------------------
115/* */
116string flNotDir(string File)
117{
118 string::size_type Res = File.rfind('/');
119 if (Res == string::npos)
120 return File;
121 Res++;
122 return string(File,Res,Res - File.length());
123}
124 /*}}}*/
d38b7b3d
AL
125// flNotFile - Strip the file from the directory name /*{{{*/
126// ---------------------------------------------------------------------
127/* */
128string flNotFile(string File)
129{
130 string::size_type Res = File.rfind('/');
131 if (Res == string::npos)
132 return File;
133 Res++;
134 return string(File,0,Res);
135}
136 /*}}}*/
3b5421b4
AL
137// SetCloseExec - Set the close on exec flag /*{{{*/
138// ---------------------------------------------------------------------
139/* */
140void SetCloseExec(int Fd,bool Close)
141{
142 if (fcntl(Fd,F_SETFD,(Close == false)?0:FD_CLOEXEC) != 0)
143 {
144 cerr << "FATAL -> Could not set close on exec " << strerror(errno) << endl;
145 exit(100);
146 }
147}
148 /*}}}*/
149// SetNonBlock - Set the nonblocking flag /*{{{*/
150// ---------------------------------------------------------------------
151/* */
152void SetNonBlock(int Fd,bool Block)
153{
0a8a80e5
AL
154 int Flags = fcntl(Fd,F_GETFL) & (~O_NONBLOCK);
155 if (fcntl(Fd,F_SETFL,Flags | ((Block == false)?0:O_NONBLOCK)) != 0)
3b5421b4
AL
156 {
157 cerr << "FATAL -> Could not set non-blocking flag " << strerror(errno) << endl;
158 exit(100);
159 }
160}
161 /*}}}*/
162// WaitFd - Wait for a FD to become readable /*{{{*/
163// ---------------------------------------------------------------------
164/* This waits for a FD to become readable using select. It is usefull for
165 applications making use of non-blocking sockets. */
166bool WaitFd(int Fd)
167{
168 fd_set Set;
169 FD_ZERO(&Set);
170 FD_SET(Fd,&Set);
0a8a80e5 171
3b5421b4
AL
172 if (select(Fd+1,&Set,0,0,0) <= 0)
173 return false;
0a8a80e5 174
3b5421b4
AL
175 return true;
176}
177 /*}}}*/
578bfd0a 178
8e06abb2 179// FileFd::FileFd - Open a file /*{{{*/
578bfd0a
AL
180// ---------------------------------------------------------------------
181/* The most commonly used open mode combinations are given with Mode */
8e06abb2 182FileFd::FileFd(string FileName,OpenMode Mode, unsigned long Perms)
578bfd0a 183{
1164783d 184 Flags = AutoClose;
578bfd0a
AL
185 switch (Mode)
186 {
187 case ReadOnly:
188 iFd = open(FileName.c_str(),O_RDONLY);
189 break;
190
191 case WriteEmpty:
50b513a1
AL
192 {
193 struct stat Buf;
194 if (stat(FileName.c_str(),&Buf) == 0 && S_ISLNK(Buf.st_mode))
195 unlink(FileName.c_str());
196 iFd = open(FileName.c_str(),O_RDWR | O_CREAT | O_TRUNC,Perms);
197 break;
198 }
578bfd0a
AL
199
200 case WriteExists:
201 iFd = open(FileName.c_str(),O_RDWR);
202 break;
0a8e3465
AL
203
204 case WriteAny:
205 iFd = open(FileName.c_str(),O_RDWR | O_CREAT,Perms);
d38b7b3d 206 break;
578bfd0a
AL
207 }
208
209 if (iFd < 0)
210 _error->Errno("open","Could not open file %s",FileName.c_str());
211 else
4b4fd143 212 {
578bfd0a 213 this->FileName = FileName;
4b4fd143
AL
214 SetCloseExec(iFd,true);
215 }
578bfd0a
AL
216}
217 /*}}}*/
8e06abb2 218// FileFd::~File - Closes the file /*{{{*/
578bfd0a
AL
219// ---------------------------------------------------------------------
220/* If the proper modes are selected then we close the Fd and possibly
221 unlink the file on error. */
8e06abb2 222FileFd::~FileFd()
578bfd0a
AL
223{
224 Close();
225}
226 /*}}}*/
8e06abb2 227// FileFd::Read - Read a bit of the file /*{{{*/
578bfd0a
AL
228// ---------------------------------------------------------------------
229/* */
8e06abb2 230bool FileFd::Read(void *To,unsigned long Size)
578bfd0a
AL
231{
232 if (read(iFd,To,Size) != (signed)Size)
233 {
234 Flags |= Fail;
235 return _error->Errno("read","Read error");
236 }
237
238 return true;
239}
240 /*}}}*/
8e06abb2 241// FileFd::Write - Write to the file /*{{{*/
578bfd0a
AL
242// ---------------------------------------------------------------------
243/* */
a05599f1 244bool FileFd::Write(const void *From,unsigned long Size)
578bfd0a
AL
245{
246 if (write(iFd,From,Size) != (signed)Size)
247 {
248 Flags |= Fail;
249 return _error->Errno("write","Write error");
250 }
251
252 return true;
253}
254 /*}}}*/
8e06abb2 255// FileFd::Seek - Seek in the file /*{{{*/
578bfd0a
AL
256// ---------------------------------------------------------------------
257/* */
8e06abb2 258bool FileFd::Seek(unsigned long To)
578bfd0a
AL
259{
260 if (lseek(iFd,To,SEEK_SET) != (signed)To)
261 {
262 Flags |= Fail;
263 return _error->Error("Unable to seek to %u",To);
264 }
265
266 return true;
267}
268 /*}}}*/
7f25bdff
AL
269// FileFd::Tell - Current seek position /*{{{*/
270// ---------------------------------------------------------------------
271/* */
272unsigned long FileFd::Tell()
273{
274 off_t Res = lseek(iFd,0,SEEK_CUR);
275 if (Res == (off_t)-1)
276 _error->Errno("lseek","Failed to determine the current file position");
277 return Res;
278}
279 /*}}}*/
8e06abb2 280// FileFd::Size - Return the size of the file /*{{{*/
578bfd0a
AL
281// ---------------------------------------------------------------------
282/* */
8e06abb2 283unsigned long FileFd::Size()
578bfd0a
AL
284{
285 struct stat Buf;
286 if (fstat(iFd,&Buf) != 0)
287 return _error->Errno("fstat","Unable to determine the file size");
288 return Buf.st_size;
289}
290 /*}}}*/
8e06abb2 291// FileFd::Close - Close the file if the close flag is set /*{{{*/
578bfd0a
AL
292// ---------------------------------------------------------------------
293/* */
8e06abb2 294bool FileFd::Close()
578bfd0a
AL
295{
296 bool Res = true;
297 if ((Flags & AutoClose) == AutoClose)
1164783d 298 if (iFd >= 0 && close(iFd) != 0)
578bfd0a 299 Res &= _error->Errno("close","Problem closing the file");
1164783d
AL
300 iFd = -1;
301
578bfd0a
AL
302 if ((Flags & Fail) == Fail && (Flags & DelOnFail) == DelOnFail &&
303 FileName.empty() == false)
304 if (unlink(FileName.c_str()) != 0)
305 Res &= _error->Warning("unlnk","Problem unlinking the file");
306 return Res;
307}
308 /*}}}*/