]> git.saurik.com Git - apt.git/blame - apt-pkg/contrib/fileutl.cc
Minor fixes for FTP support
[apt.git] / apt-pkg / contrib / fileutl.cc
CommitLineData
578bfd0a
AL
1// -*- mode: cpp; mode: fold -*-
2// Description /*{{{*/
6d5dd02a 3// $Id: fileutl.cc,v 1.22 1999/03/15 08:10:39 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>
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
6d5dd02a
AL
167 applications making use of non-blocking sockets. The timeout is
168 in seconds. */
1084d58a 169bool WaitFd(int Fd,bool write,unsigned long timeout)
3b5421b4
AL
170{
171 fd_set Set;
cc2313b7 172 struct timeval tv;
3b5421b4
AL
173 FD_ZERO(&Set);
174 FD_SET(Fd,&Set);
6d5dd02a
AL
175 tv.tv_sec = timeout;
176 tv.tv_usec = 0;
1084d58a
AL
177 if (write == true)
178 {
179 if (select(Fd+1,0,&Set,0,(timeout != 0?&tv:0)) <= 0)
cc2313b7 180 return false;
1084d58a
AL
181 }
182 else
183 {
184 if (select(Fd+1,&Set,0,0,(timeout != 0?&tv:0)) <= 0)
cc2313b7
AL
185 return false;
186 }
1084d58a 187
3b5421b4
AL
188 return true;
189}
190 /*}}}*/
578bfd0a 191
8e06abb2 192// FileFd::FileFd - Open a file /*{{{*/
578bfd0a
AL
193// ---------------------------------------------------------------------
194/* The most commonly used open mode combinations are given with Mode */
8e06abb2 195FileFd::FileFd(string FileName,OpenMode Mode, unsigned long Perms)
578bfd0a 196{
1164783d 197 Flags = AutoClose;
578bfd0a
AL
198 switch (Mode)
199 {
200 case ReadOnly:
201 iFd = open(FileName.c_str(),O_RDONLY);
202 break;
203
204 case WriteEmpty:
50b513a1
AL
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 }
578bfd0a
AL
212
213 case WriteExists:
214 iFd = open(FileName.c_str(),O_RDWR);
215 break;
0a8e3465
AL
216
217 case WriteAny:
218 iFd = open(FileName.c_str(),O_RDWR | O_CREAT,Perms);
d38b7b3d 219 break;
578bfd0a
AL
220 }
221
222 if (iFd < 0)
223 _error->Errno("open","Could not open file %s",FileName.c_str());
224 else
4b4fd143 225 {
578bfd0a 226 this->FileName = FileName;
4b4fd143
AL
227 SetCloseExec(iFd,true);
228 }
578bfd0a
AL
229}
230 /*}}}*/
8e06abb2 231// FileFd::~File - Closes the file /*{{{*/
578bfd0a
AL
232// ---------------------------------------------------------------------
233/* If the proper modes are selected then we close the Fd and possibly
234 unlink the file on error. */
8e06abb2 235FileFd::~FileFd()
578bfd0a
AL
236{
237 Close();
238}
239 /*}}}*/
8e06abb2 240// FileFd::Read - Read a bit of the file /*{{{*/
578bfd0a
AL
241// ---------------------------------------------------------------------
242/* */
8e06abb2 243bool FileFd::Read(void *To,unsigned long Size)
578bfd0a
AL
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 /*}}}*/
8e06abb2 254// FileFd::Write - Write to the file /*{{{*/
578bfd0a
AL
255// ---------------------------------------------------------------------
256/* */
a05599f1 257bool FileFd::Write(const void *From,unsigned long Size)
578bfd0a
AL
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 /*}}}*/
8e06abb2 268// FileFd::Seek - Seek in the file /*{{{*/
578bfd0a
AL
269// ---------------------------------------------------------------------
270/* */
8e06abb2 271bool FileFd::Seek(unsigned long To)
578bfd0a
AL
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
6d5dd02a
AL
279 return true;
280}
281 /*}}}*/
282// FileFd::Truncate - Truncate the file /*{{{*/
283// ---------------------------------------------------------------------
284/* */
285bool 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
578bfd0a
AL
293 return true;
294}
295 /*}}}*/
7f25bdff
AL
296// FileFd::Tell - Current seek position /*{{{*/
297// ---------------------------------------------------------------------
298/* */
299unsigned 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 /*}}}*/
8e06abb2 307// FileFd::Size - Return the size of the file /*{{{*/
578bfd0a
AL
308// ---------------------------------------------------------------------
309/* */
8e06abb2 310unsigned long FileFd::Size()
578bfd0a
AL
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 /*}}}*/
8e06abb2 318// FileFd::Close - Close the file if the close flag is set /*{{{*/
578bfd0a
AL
319// ---------------------------------------------------------------------
320/* */
8e06abb2 321bool FileFd::Close()
578bfd0a
AL
322{
323 bool Res = true;
324 if ((Flags & AutoClose) == AutoClose)
1164783d 325 if (iFd >= 0 && close(iFd) != 0)
578bfd0a 326 Res &= _error->Errno("close","Problem closing the file");
1164783d
AL
327 iFd = -1;
328
578bfd0a
AL
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 /*}}}*/