Sync
[ntk/apt.git] / apt-pkg / contrib / fileutl.cc
1 // -*- mode: cpp; mode: fold -*-
2 // Description /*{{{*/
3 // $Id: fileutl.cc,v 1.11 1998/10/22 04:56:47 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 // SetCloseExec - Set the close on exec flag /*{{{*/
123 // ---------------------------------------------------------------------
124 /* */
125 void SetCloseExec(int Fd,bool Close)
126 {
127 if (fcntl(Fd,F_SETFD,(Close == false)?0:FD_CLOEXEC) != 0)
128 {
129 cerr << "FATAL -> Could not set close on exec " << strerror(errno) << endl;
130 exit(100);
131 }
132 }
133 /*}}}*/
134 // SetNonBlock - Set the nonblocking flag /*{{{*/
135 // ---------------------------------------------------------------------
136 /* */
137 void SetNonBlock(int Fd,bool Block)
138 {
139 int Flags = fcntl(Fd,F_GETFL) & (~O_NONBLOCK);
140 if (fcntl(Fd,F_SETFL,Flags | ((Block == false)?0:O_NONBLOCK)) != 0)
141 {
142 cerr << "FATAL -> Could not set non-blocking flag " << strerror(errno) << endl;
143 exit(100);
144 }
145 }
146 /*}}}*/
147 // WaitFd - Wait for a FD to become readable /*{{{*/
148 // ---------------------------------------------------------------------
149 /* This waits for a FD to become readable using select. It is usefull for
150 applications making use of non-blocking sockets. */
151 bool WaitFd(int Fd)
152 {
153 fd_set Set;
154 FD_ZERO(&Set);
155 FD_SET(Fd,&Set);
156
157 if (select(Fd+1,&Set,0,0,0) <= 0)
158 return false;
159
160 return true;
161 }
162 /*}}}*/
163
164 // FileFd::FileFd - Open a file /*{{{*/
165 // ---------------------------------------------------------------------
166 /* The most commonly used open mode combinations are given with Mode */
167 FileFd::FileFd(string FileName,OpenMode Mode, unsigned long Perms)
168 {
169 Flags = AutoClose;
170 switch (Mode)
171 {
172 case ReadOnly:
173 iFd = open(FileName.c_str(),O_RDONLY);
174 break;
175
176 case WriteEmpty:
177 unlink(FileName.c_str());
178 iFd = open(FileName.c_str(),O_RDWR | O_CREAT | O_EXCL,Perms);
179 break;
180
181 case WriteExists:
182 iFd = open(FileName.c_str(),O_RDWR);
183 break;
184
185 case WriteAny:
186 iFd = open(FileName.c_str(),O_RDWR | O_CREAT,Perms);
187 break;
188
189 // Dont use this in public directories
190 case LockEmpty:
191 iFd = open(FileName.c_str(),O_RDWR | O_CREAT | O_TRUNC,Perms);
192 break;
193 }
194
195 if (iFd < 0)
196 _error->Errno("open","Could not open file %s",FileName.c_str());
197 else
198 this->FileName = FileName;
199 SetCloseExec(iFd,true);
200 }
201 /*}}}*/
202 // FileFd::~File - Closes the file /*{{{*/
203 // ---------------------------------------------------------------------
204 /* If the proper modes are selected then we close the Fd and possibly
205 unlink the file on error. */
206 FileFd::~FileFd()
207 {
208 Close();
209 }
210 /*}}}*/
211 // FileFd::Read - Read a bit of the file /*{{{*/
212 // ---------------------------------------------------------------------
213 /* */
214 bool FileFd::Read(void *To,unsigned long Size)
215 {
216 if (read(iFd,To,Size) != (signed)Size)
217 {
218 Flags |= Fail;
219 return _error->Errno("read","Read error");
220 }
221
222 return true;
223 }
224 /*}}}*/
225 // FileFd::Write - Write to the file /*{{{*/
226 // ---------------------------------------------------------------------
227 /* */
228 bool FileFd::Write(void *From,unsigned long Size)
229 {
230 if (write(iFd,From,Size) != (signed)Size)
231 {
232 Flags |= Fail;
233 return _error->Errno("write","Write error");
234 }
235
236 return true;
237 }
238 /*}}}*/
239 // FileFd::Seek - Seek in the file /*{{{*/
240 // ---------------------------------------------------------------------
241 /* */
242 bool FileFd::Seek(unsigned long To)
243 {
244 if (lseek(iFd,To,SEEK_SET) != (signed)To)
245 {
246 Flags |= Fail;
247 return _error->Error("Unable to seek to %u",To);
248 }
249
250 return true;
251 }
252 /*}}}*/
253 // FileFd::Size - Return the size of the file /*{{{*/
254 // ---------------------------------------------------------------------
255 /* */
256 unsigned long FileFd::Size()
257 {
258 struct stat Buf;
259 if (fstat(iFd,&Buf) != 0)
260 return _error->Errno("fstat","Unable to determine the file size");
261 return Buf.st_size;
262 }
263 /*}}}*/
264 // FileFd::Close - Close the file if the close flag is set /*{{{*/
265 // ---------------------------------------------------------------------
266 /* */
267 bool FileFd::Close()
268 {
269 bool Res = true;
270 if ((Flags & AutoClose) == AutoClose)
271 if (iFd >= 0 && close(iFd) != 0)
272 Res &= _error->Errno("close","Problem closing the file");
273 iFd = -1;
274
275 if ((Flags & Fail) == Fail && (Flags & DelOnFail) == DelOnFail &&
276 FileName.empty() == false)
277 if (unlink(FileName.c_str()) != 0)
278 Res &= _error->Warning("unlnk","Problem unlinking the file");
279 return Res;
280 }
281 /*}}}*/