]> git.saurik.com Git - apt.git/blob - apt-pkg/contrib/fileutl.cc
CDROM patches from bluehorn
[apt.git] / apt-pkg / contrib / fileutl.cc
1 // -*- mode: cpp; mode: fold -*-
2 // Description /*{{{*/
3 // $Id: fileutl.cc,v 1.26 1999/03/21 07:24:14 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 unsigned long Size = From.Size();
42 while (Size != 0)
43 {
44 unsigned long ToRead = Size;
45 if (Size > 64000)
46 ToRead = 64000;
47
48 if (From.Read(Buf,ToRead) == false ||
49 To.Write(Buf,ToRead) == false)
50 {
51 delete [] Buf;
52 return false;
53 }
54
55 Size -= ToRead;
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. */
68 int 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;
80 fl.l_type = F_WRLCK;
81 fl.l_whence = SEEK_SET;
82 fl.l_start = 0;
83 fl.l_len = 0;
84 if (fcntl(FD,F_SETLK,&fl) == -1)
85 {
86 if (errno == ENOLCK)
87 {
88 _error->Warning("Not using locking for nfs mounted lock file %s",File.c_str());
89 return true;
90 }
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 /* */
103 bool 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. */
114 string SafeGetCWD()
115 {
116 // Stash the current dir.
117 char S[300];
118 S[0] = 0;
119 if (getcwd(S,sizeof(S)-2) == 0)
120 return "/";
121 unsigned int Len = strlen(S);
122 S[Len] = '/';
123 S[Len+1] = 0;
124 return S;
125 }
126 /*}}}*/
127 // flNotDir - Strip the directory from the filename /*{{{*/
128 // ---------------------------------------------------------------------
129 /* */
130 string 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 /*}}}*/
139 // flNotFile - Strip the file from the directory name /*{{{*/
140 // ---------------------------------------------------------------------
141 /* */
142 string 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 /*}}}*/
151 // SetCloseExec - Set the close on exec flag /*{{{*/
152 // ---------------------------------------------------------------------
153 /* */
154 void 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 /* */
166 void SetNonBlock(int Fd,bool Block)
167 {
168 int Flags = fcntl(Fd,F_GETFL) & (~O_NONBLOCK);
169 if (fcntl(Fd,F_SETFL,Flags | ((Block == false)?0:O_NONBLOCK)) != 0)
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
179 applications making use of non-blocking sockets. The timeout is
180 in seconds. */
181 bool WaitFd(int Fd,bool write,unsigned long timeout)
182 {
183 fd_set Set;
184 struct timeval tv;
185 FD_ZERO(&Set);
186 FD_SET(Fd,&Set);
187 tv.tv_sec = timeout;
188 tv.tv_usec = 0;
189 if (write == true)
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;
200 }
201 else
202 {
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;
212 }
213
214 return true;
215 }
216 /*}}}*/
217
218 // FileFd::FileFd - Open a file /*{{{*/
219 // ---------------------------------------------------------------------
220 /* The most commonly used open mode combinations are given with Mode */
221 FileFd::FileFd(string FileName,OpenMode Mode, unsigned long Perms)
222 {
223 Flags = AutoClose;
224 switch (Mode)
225 {
226 case ReadOnly:
227 iFd = open(FileName.c_str(),O_RDONLY);
228 break;
229
230 case WriteEmpty:
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 }
238
239 case WriteExists:
240 iFd = open(FileName.c_str(),O_RDWR);
241 break;
242
243 case WriteAny:
244 iFd = open(FileName.c_str(),O_RDWR | O_CREAT,Perms);
245 break;
246 }
247
248 if (iFd < 0)
249 _error->Errno("open","Could not open file %s",FileName.c_str());
250 else
251 {
252 this->FileName = FileName;
253 SetCloseExec(iFd,true);
254 }
255 }
256 /*}}}*/
257 // FileFd::~File - Closes the file /*{{{*/
258 // ---------------------------------------------------------------------
259 /* If the proper modes are selected then we close the Fd and possibly
260 unlink the file on error. */
261 FileFd::~FileFd()
262 {
263 Close();
264 }
265 /*}}}*/
266 // FileFd::Read - Read a bit of the file /*{{{*/
267 // ---------------------------------------------------------------------
268 /* We are carefull to handle interruption by a signal while reading
269 gracefully. */
270 bool FileFd::Read(void *To,unsigned long Size)
271 {
272 int Res;
273 errno = 0;
274 do
275 {
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 }
284
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);
295 }
296 /*}}}*/
297 // FileFd::Write - Write to the file /*{{{*/
298 // ---------------------------------------------------------------------
299 /* */
300 bool FileFd::Write(const void *From,unsigned long Size)
301 {
302 int Res;
303 errno = 0;
304 do
305 {
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;
317 }
318 while (Res > 0 && Size > 0);
319
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);
325 }
326 /*}}}*/
327 // FileFd::Seek - Seek in the file /*{{{*/
328 // ---------------------------------------------------------------------
329 /* */
330 bool FileFd::Seek(unsigned long To)
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
338 return true;
339 }
340 /*}}}*/
341 // FileFd::Truncate - Truncate the file /*{{{*/
342 // ---------------------------------------------------------------------
343 /* */
344 bool 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
352 return true;
353 }
354 /*}}}*/
355 // FileFd::Tell - Current seek position /*{{{*/
356 // ---------------------------------------------------------------------
357 /* */
358 unsigned 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 /*}}}*/
366 // FileFd::Size - Return the size of the file /*{{{*/
367 // ---------------------------------------------------------------------
368 /* */
369 unsigned long FileFd::Size()
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 /*}}}*/
377 // FileFd::Close - Close the file if the close flag is set /*{{{*/
378 // ---------------------------------------------------------------------
379 /* */
380 bool FileFd::Close()
381 {
382 bool Res = true;
383 if ((Flags & AutoClose) == AutoClose)
384 if (iFd >= 0 && close(iFd) != 0)
385 Res &= _error->Errno("close","Problem closing the file");
386 iFd = -1;
387
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 /*}}}*/