Sync
[ntk/apt.git] / apt-pkg / contrib / fileutl.cc
1 // -*- mode: cpp; mode: fold -*-
2 // Description /*{{{*/
3 // $Id: fileutl.cc,v 1.8 1998/10/02 04:39:50 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
123 // FileFd::FileFd - Open a file /*{{{*/
124 // ---------------------------------------------------------------------
125 /* The most commonly used open mode combinations are given with Mode */
126 FileFd::FileFd(string FileName,OpenMode Mode, unsigned long Perms)
127 {
128 Flags = AutoClose;
129 switch (Mode)
130 {
131 case ReadOnly:
132 iFd = open(FileName.c_str(),O_RDONLY);
133 break;
134
135 case WriteEmpty:
136 unlink(FileName.c_str());
137 iFd = open(FileName.c_str(),O_RDWR | O_CREAT | O_EXCL,Perms);
138 break;
139
140 case WriteExists:
141 iFd = open(FileName.c_str(),O_RDWR);
142 break;
143
144 case WriteAny:
145 iFd = open(FileName.c_str(),O_RDWR | O_CREAT,Perms);
146 break;
147
148 // Dont use this in public directories
149 case LockEmpty:
150 iFd = open(FileName.c_str(),O_RDWR | O_CREAT | O_TRUNC,Perms);
151 break;
152 }
153
154 if (iFd < 0)
155 _error->Errno("open","Could not open file %s",FileName.c_str());
156 else
157 this->FileName = FileName;
158 }
159 /*}}}*/
160 // FileFd::~File - Closes the file /*{{{*/
161 // ---------------------------------------------------------------------
162 /* If the proper modes are selected then we close the Fd and possibly
163 unlink the file on error. */
164 FileFd::~FileFd()
165 {
166 Close();
167 }
168 /*}}}*/
169 // FileFd::Read - Read a bit of the file /*{{{*/
170 // ---------------------------------------------------------------------
171 /* */
172 bool FileFd::Read(void *To,unsigned long Size)
173 {
174 if (read(iFd,To,Size) != (signed)Size)
175 {
176 Flags |= Fail;
177 return _error->Errno("read","Read error");
178 }
179
180 return true;
181 }
182 /*}}}*/
183 // FileFd::Write - Write to the file /*{{{*/
184 // ---------------------------------------------------------------------
185 /* */
186 bool FileFd::Write(void *From,unsigned long Size)
187 {
188 if (write(iFd,From,Size) != (signed)Size)
189 {
190 Flags |= Fail;
191 return _error->Errno("write","Write error");
192 }
193
194 return true;
195 }
196 /*}}}*/
197 // FileFd::Seek - Seek in the file /*{{{*/
198 // ---------------------------------------------------------------------
199 /* */
200 bool FileFd::Seek(unsigned long To)
201 {
202 if (lseek(iFd,To,SEEK_SET) != (signed)To)
203 {
204 Flags |= Fail;
205 return _error->Error("Unable to seek to %u",To);
206 }
207
208 return true;
209 }
210 /*}}}*/
211 // FileFd::Size - Return the size of the file /*{{{*/
212 // ---------------------------------------------------------------------
213 /* */
214 unsigned long FileFd::Size()
215 {
216 struct stat Buf;
217 if (fstat(iFd,&Buf) != 0)
218 return _error->Errno("fstat","Unable to determine the file size");
219 return Buf.st_size;
220 }
221 /*}}}*/
222 // FileFd::Close - Close the file if the close flag is set /*{{{*/
223 // ---------------------------------------------------------------------
224 /* */
225 bool FileFd::Close()
226 {
227 bool Res = true;
228 if ((Flags & AutoClose) == AutoClose)
229 if (iFd >= 0 && close(iFd) != 0)
230 Res &= _error->Errno("close","Problem closing the file");
231 iFd = -1;
232
233 if ((Flags & Fail) == Fail && (Flags & DelOnFail) == DelOnFail &&
234 FileName.empty() == false)
235 if (unlink(FileName.c_str()) != 0)
236 Res &= _error->Warning("unlnk","Problem unlinking the file");
237 return Res;
238 }
239 /*}}}*/