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