Minor fixes for FTP support
[ntk/apt.git] / apt-pkg / contrib / fileutl.cc
1 // -*- mode: cpp; mode: fold -*-
2 // Description /*{{{*/
3 // $Id: fileutl.cc,v 1.22 1999/03/15 08:10:39 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. The timeout is
168 in seconds. */
169 bool WaitFd(int Fd,bool write,unsigned long timeout)
170 {
171 fd_set Set;
172 struct timeval tv;
173 FD_ZERO(&Set);
174 FD_SET(Fd,&Set);
175 tv.tv_sec = timeout;
176 tv.tv_usec = 0;
177 if (write == true)
178 {
179 if (select(Fd+1,0,&Set,0,(timeout != 0?&tv:0)) <= 0)
180 return false;
181 }
182 else
183 {
184 if (select(Fd+1,&Set,0,0,(timeout != 0?&tv:0)) <= 0)
185 return false;
186 }
187
188 return true;
189 }
190 /*}}}*/
191
192 // FileFd::FileFd - Open a file /*{{{*/
193 // ---------------------------------------------------------------------
194 /* The most commonly used open mode combinations are given with Mode */
195 FileFd::FileFd(string FileName,OpenMode Mode, unsigned long Perms)
196 {
197 Flags = AutoClose;
198 switch (Mode)
199 {
200 case ReadOnly:
201 iFd = open(FileName.c_str(),O_RDONLY);
202 break;
203
204 case WriteEmpty:
205 {
206 struct stat Buf;
207 if (stat(FileName.c_str(),&Buf) == 0 && S_ISLNK(Buf.st_mode))
208 unlink(FileName.c_str());
209 iFd = open(FileName.c_str(),O_RDWR | O_CREAT | O_TRUNC,Perms);
210 break;
211 }
212
213 case WriteExists:
214 iFd = open(FileName.c_str(),O_RDWR);
215 break;
216
217 case WriteAny:
218 iFd = open(FileName.c_str(),O_RDWR | O_CREAT,Perms);
219 break;
220 }
221
222 if (iFd < 0)
223 _error->Errno("open","Could not open file %s",FileName.c_str());
224 else
225 {
226 this->FileName = FileName;
227 SetCloseExec(iFd,true);
228 }
229 }
230 /*}}}*/
231 // FileFd::~File - Closes the file /*{{{*/
232 // ---------------------------------------------------------------------
233 /* If the proper modes are selected then we close the Fd and possibly
234 unlink the file on error. */
235 FileFd::~FileFd()
236 {
237 Close();
238 }
239 /*}}}*/
240 // FileFd::Read - Read a bit of the file /*{{{*/
241 // ---------------------------------------------------------------------
242 /* */
243 bool FileFd::Read(void *To,unsigned long Size)
244 {
245 if (read(iFd,To,Size) != (signed)Size)
246 {
247 Flags |= Fail;
248 return _error->Errno("read","Read error");
249 }
250
251 return true;
252 }
253 /*}}}*/
254 // FileFd::Write - Write to the file /*{{{*/
255 // ---------------------------------------------------------------------
256 /* */
257 bool FileFd::Write(const void *From,unsigned long Size)
258 {
259 if (write(iFd,From,Size) != (signed)Size)
260 {
261 Flags |= Fail;
262 return _error->Errno("write","Write error");
263 }
264
265 return true;
266 }
267 /*}}}*/
268 // FileFd::Seek - Seek in the file /*{{{*/
269 // ---------------------------------------------------------------------
270 /* */
271 bool FileFd::Seek(unsigned long To)
272 {
273 if (lseek(iFd,To,SEEK_SET) != (signed)To)
274 {
275 Flags |= Fail;
276 return _error->Error("Unable to seek to %u",To);
277 }
278
279 return true;
280 }
281 /*}}}*/
282 // FileFd::Truncate - Truncate the file /*{{{*/
283 // ---------------------------------------------------------------------
284 /* */
285 bool FileFd::Truncate(unsigned long To)
286 {
287 if (ftruncate(iFd,To) != 0)
288 {
289 Flags |= Fail;
290 return _error->Error("Unable to truncate to %u",To);
291 }
292
293 return true;
294 }
295 /*}}}*/
296 // FileFd::Tell - Current seek position /*{{{*/
297 // ---------------------------------------------------------------------
298 /* */
299 unsigned long FileFd::Tell()
300 {
301 off_t Res = lseek(iFd,0,SEEK_CUR);
302 if (Res == (off_t)-1)
303 _error->Errno("lseek","Failed to determine the current file position");
304 return Res;
305 }
306 /*}}}*/
307 // FileFd::Size - Return the size of the file /*{{{*/
308 // ---------------------------------------------------------------------
309 /* */
310 unsigned long FileFd::Size()
311 {
312 struct stat Buf;
313 if (fstat(iFd,&Buf) != 0)
314 return _error->Errno("fstat","Unable to determine the file size");
315 return Buf.st_size;
316 }
317 /*}}}*/
318 // FileFd::Close - Close the file if the close flag is set /*{{{*/
319 // ---------------------------------------------------------------------
320 /* */
321 bool FileFd::Close()
322 {
323 bool Res = true;
324 if ((Flags & AutoClose) == AutoClose)
325 if (iFd >= 0 && close(iFd) != 0)
326 Res &= _error->Errno("close","Problem closing the file");
327 iFd = -1;
328
329 if ((Flags & Fail) == Fail && (Flags & DelOnFail) == DelOnFail &&
330 FileName.empty() == false)
331 if (unlink(FileName.c_str()) != 0)
332 Res &= _error->Warning("unlnk","Problem unlinking the file");
333 return Res;
334 }
335 /*}}}*/