]> git.saurik.com Git - apt.git/blob - apt-pkg/contrib/fileutl.cc
Fixed WaitFD
[apt.git] / apt-pkg / contrib / fileutl.cc
1 // -*- mode: cpp; mode: fold -*-
2 // Description /*{{{*/
3 // $Id: fileutl.cc,v 1.21 1999/02/16 04:18:35 jgg Exp $
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 /*{{{*/
17 #ifdef __GNUG__
18 #pragma implementation "apt-pkg/fileutl.h"
19 #endif
20 #include <apt-pkg/fileutl.h>
21 #include <apt-pkg/error.h>
22
23 #include <unistd.h>
24 #include <sys/stat.h>
25 #include <sys/fcntl.h>
26 #include <sys/types.h>
27 #include <sys/time.h>
28 #include <errno.h>
29 /*}}}*/
30
31 // CopyFile - Buffered copy of a file /*{{{*/
32 // ---------------------------------------------------------------------
33 /* The caller is expected to set things so that failure causes erasure */
34 bool CopyFile(FileFd &From,FileFd &To)
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. */
61 int 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;
73 fl.l_type = F_WRLCK;
74 fl.l_whence = SEEK_SET;
75 fl.l_start = 0;
76 fl.l_len = 0;
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 /* */
91 bool 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. */
102 string SafeGetCWD()
103 {
104 // Stash the current dir.
105 char S[300];
106 S[0] = 0;
107 if (getcwd(S,sizeof(S)-2) == 0)
108 return "/";
109 unsigned int Len = strlen(S);
110 S[Len] = '/';
111 S[Len+1] = 0;
112 return S;
113 }
114 /*}}}*/
115 // flNotDir - Strip the directory from the filename /*{{{*/
116 // ---------------------------------------------------------------------
117 /* */
118 string 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 /*}}}*/
127 // flNotFile - Strip the file from the directory name /*{{{*/
128 // ---------------------------------------------------------------------
129 /* */
130 string 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 /*}}}*/
139 // SetCloseExec - Set the close on exec flag /*{{{*/
140 // ---------------------------------------------------------------------
141 /* */
142 void 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 /* */
154 void SetNonBlock(int Fd,bool Block)
155 {
156 int Flags = fcntl(Fd,F_GETFL) & (~O_NONBLOCK);
157 if (fcntl(Fd,F_SETFL,Flags | ((Block == false)?0:O_NONBLOCK)) != 0)
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. */
168 bool WaitFd(int Fd,bool write,unsigned long timeout)
169 {
170 fd_set Set;
171 struct timeval tv;
172 FD_ZERO(&Set);
173 FD_SET(Fd,&Set);
174 tv.tv_sec = timeout / 1000000;
175 tv.tv_usec = timeout % 1000000;
176 if (write == true)
177 {
178 if (select(Fd+1,0,&Set,0,(timeout != 0?&tv:0)) <= 0)
179 return false;
180 }
181 else
182 {
183 if (select(Fd+1,&Set,0,0,(timeout != 0?&tv:0)) <= 0)
184 return false;
185 }
186
187 return true;
188 }
189 /*}}}*/
190
191 // FileFd::FileFd - Open a file /*{{{*/
192 // ---------------------------------------------------------------------
193 /* The most commonly used open mode combinations are given with Mode */
194 FileFd::FileFd(string FileName,OpenMode Mode, unsigned long Perms)
195 {
196 Flags = AutoClose;
197 switch (Mode)
198 {
199 case ReadOnly:
200 iFd = open(FileName.c_str(),O_RDONLY);
201 break;
202
203 case WriteEmpty:
204 {
205 struct stat Buf;
206 if (stat(FileName.c_str(),&Buf) == 0 && S_ISLNK(Buf.st_mode))
207 unlink(FileName.c_str());
208 iFd = open(FileName.c_str(),O_RDWR | O_CREAT | O_TRUNC,Perms);
209 break;
210 }
211
212 case WriteExists:
213 iFd = open(FileName.c_str(),O_RDWR);
214 break;
215
216 case WriteAny:
217 iFd = open(FileName.c_str(),O_RDWR | O_CREAT,Perms);
218 break;
219 }
220
221 if (iFd < 0)
222 _error->Errno("open","Could not open file %s",FileName.c_str());
223 else
224 {
225 this->FileName = FileName;
226 SetCloseExec(iFd,true);
227 }
228 }
229 /*}}}*/
230 // FileFd::~File - Closes the file /*{{{*/
231 // ---------------------------------------------------------------------
232 /* If the proper modes are selected then we close the Fd and possibly
233 unlink the file on error. */
234 FileFd::~FileFd()
235 {
236 Close();
237 }
238 /*}}}*/
239 // FileFd::Read - Read a bit of the file /*{{{*/
240 // ---------------------------------------------------------------------
241 /* */
242 bool FileFd::Read(void *To,unsigned long Size)
243 {
244 if (read(iFd,To,Size) != (signed)Size)
245 {
246 Flags |= Fail;
247 return _error->Errno("read","Read error");
248 }
249
250 return true;
251 }
252 /*}}}*/
253 // FileFd::Write - Write to the file /*{{{*/
254 // ---------------------------------------------------------------------
255 /* */
256 bool FileFd::Write(const void *From,unsigned long Size)
257 {
258 if (write(iFd,From,Size) != (signed)Size)
259 {
260 Flags |= Fail;
261 return _error->Errno("write","Write error");
262 }
263
264 return true;
265 }
266 /*}}}*/
267 // FileFd::Seek - Seek in the file /*{{{*/
268 // ---------------------------------------------------------------------
269 /* */
270 bool FileFd::Seek(unsigned long To)
271 {
272 if (lseek(iFd,To,SEEK_SET) != (signed)To)
273 {
274 Flags |= Fail;
275 return _error->Error("Unable to seek to %u",To);
276 }
277
278 return true;
279 }
280 /*}}}*/
281 // FileFd::Tell - Current seek position /*{{{*/
282 // ---------------------------------------------------------------------
283 /* */
284 unsigned long FileFd::Tell()
285 {
286 off_t Res = lseek(iFd,0,SEEK_CUR);
287 if (Res == (off_t)-1)
288 _error->Errno("lseek","Failed to determine the current file position");
289 return Res;
290 }
291 /*}}}*/
292 // FileFd::Size - Return the size of the file /*{{{*/
293 // ---------------------------------------------------------------------
294 /* */
295 unsigned long FileFd::Size()
296 {
297 struct stat Buf;
298 if (fstat(iFd,&Buf) != 0)
299 return _error->Errno("fstat","Unable to determine the file size");
300 return Buf.st_size;
301 }
302 /*}}}*/
303 // FileFd::Close - Close the file if the close flag is set /*{{{*/
304 // ---------------------------------------------------------------------
305 /* */
306 bool FileFd::Close()
307 {
308 bool Res = true;
309 if ((Flags & AutoClose) == AutoClose)
310 if (iFd >= 0 && close(iFd) != 0)
311 Res &= _error->Errno("close","Problem closing the file");
312 iFd = -1;
313
314 if ((Flags & Fail) == Fail && (Flags & DelOnFail) == DelOnFail &&
315 FileName.empty() == false)
316 if (unlink(FileName.c_str()) != 0)
317 Res &= _error->Warning("unlnk","Problem unlinking the file");
318 return Res;
319 }
320 /*}}}*/