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