]> cygwin.com Git - cygwin-apps/setup.git/blob - ini.cc
211e06e23926a4cc251ae5ffe007a048c97adc36
[cygwin-apps/setup.git] / ini.cc
1 /*
2 * Copyright (c) 2000,2007 Red Hat, Inc.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * A copy of the GNU General Public License can be found at
10 * http://www.gnu.org/
11 *
12 * Written by DJ Delorie <dj@cygnus.com>
13 *
14 */
15
16 /* The purpose of this file is to get and parse the setup.ini file
17 from the mirror site. A few support routines for the bison and
18 flex parsers are provided also. We check to see if this setup.ini
19 is older than the one we used last time, and if so, warn the user. */
20
21 #if 0
22 static const char *cvsid =
23 "\n%%% $Id$\n";
24 #endif
25
26 #include "ini.h"
27
28 #include "csu_util/rfc1738.h"
29 #include "csu_util/version_compare.h"
30
31 #include "setup_version.h"
32 #include "win32.h"
33 #include "LogSingleton.h"
34
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <stdarg.h>
38 #include <process.h>
39
40 #include "resource.h"
41 #include "state.h"
42 #include "geturl.h"
43 #include "dialog.h"
44 #include "msg.h"
45 #include "mount.h"
46 #include "site.h"
47 #include "find.h"
48 #include "IniParseFindVisitor.h"
49 #include "IniParseFeedback.h"
50
51 #include "io_stream.h"
52 #include "io_stream_memory.h"
53
54 #include "threebar.h"
55
56 #include "IniDBBuilderPackage.h"
57 #include "compress.h"
58 #include "Exception.h"
59
60 extern ThreeBarProgressPage Progress;
61
62 unsigned int setup_timestamp = 0;
63 std::string ini_setup_version;
64
65 extern int yyparse ();
66 /*extern int yydebug;*/
67
68 class GuiParseFeedback : public IniParseFeedback
69 {
70 public:
71 GuiParseFeedback () : lastpct (0)
72 {
73 Progress.SetText2 ("");
74 Progress.SetText3 ("");
75 Progress.SetText4 ("Progress:");
76 }
77 virtual void progress(unsigned long const pos, unsigned long const max)
78 {
79 if (!max)
80 /* length not known or eof */
81 return;
82 if (lastpct == 100)
83 /* rounding down should mean this only ever fires once */
84 lastpct = 0;
85 if (pos * 100 / max > lastpct)
86 {
87 lastpct = pos * 100 / max;
88 /* log (LOG_BABBLE) << lastpct << "% (" << pos << " of " << max
89 << " bytes of ini file read)" << endLog; */
90 }
91 Progress.SetBar1(pos, max);
92 }
93 virtual void iniName (const std::string& name)
94 {
95 Progress.SetText1 (("Parsing ini file \"" + name + "\"").c_str());
96 }
97 virtual void babble(const std::string& message)const
98 {
99 log (LOG_BABBLE) << message << endLog;
100 }
101 virtual void warning (const std::string& message)const
102 {
103 MessageBox (0, message.c_str(), "Warning", 0);
104 }
105 virtual void error(const std::string& message)const
106 {
107 MessageBox (0, message.c_str(), "Parse Errors", 0);
108 }
109 virtual ~ GuiParseFeedback ()
110 {
111 Progress.SetText4("Package:");
112 }
113 private:
114 unsigned int lastpct;
115 };
116
117 static int
118 do_local_ini (HWND owner)
119 {
120 GuiParseFeedback myFeedback;
121 IniDBBuilderPackage findBuilder(myFeedback);
122 IniParseFindVisitor myVisitor (findBuilder, local_dir, myFeedback);
123 Find (local_dir).accept(myVisitor);
124 setup_timestamp = myVisitor.timeStamp();
125 ini_setup_version = myVisitor.version();
126 return myVisitor.iniCount();
127 }
128
129 static int
130 do_remote_ini (HWND owner)
131 {
132 size_t ini_count = 0;
133 GuiParseFeedback myFeedback;
134 IniDBBuilderPackage aBuilder(myFeedback);
135 io_stream *ini_file;
136
137 /* FIXME: Get rid of this io_stream pointer travesty. The need to
138 explicitly delete these things is ridiculous. Note that the
139 decompress io_stream "owns" the underlying compressed io_stream
140 instance, so it should not be deleted explicitly. */
141
142 for (SiteList::const_iterator n = site_list.begin();
143 n != site_list.end(); ++n)
144 {
145
146 /* First try to fetch the .bz2 compressed ini file. */
147 current_ini_name = n->url + "/" + SETUP_BZ2_FILENAME;
148 if ((ini_file = get_url_to_membuf (current_ini_name, owner)))
149 {
150 /* Decompress the entire file in memory right now. This has the
151 advantage that input_stream->get_size() will work during parsing
152 and we'll have an accurate status bar. Also, we can't seek
153 bz2 streams, so when it comes time to write out a local cached
154 copy of the .ini file below, we'd otherwise have to delete this
155 stream and uncompress it again from the start, which is wasteful.
156 The current uncompresed size of the .ini file as of 2007 is less
157 than 600 kB, so this is not a great deal of memory. */
158 io_stream *bz2_stream = compress::decompress (ini_file);
159 if (!bz2_stream)
160 {
161 /* This isn't a valid bz2 file. */
162 delete ini_file;
163 ini_file = NULL;
164 }
165 else
166 {
167 io_stream *uncompressed = new io_stream_memory ();
168
169 if (io_stream::copy (bz2_stream, uncompressed) != 0 ||
170 bz2_stream->error () == EIO)
171 {
172 /* There was a problem decompressing bz2. */
173 delete bz2_stream;
174 delete uncompressed;
175 ini_file = NULL;
176 log (LOG_PLAIN) <<
177 "Warning: Problem encountered while uncompressing " <<
178 current_ini_name << " - possibly truncated or corrupt bzip2"
179 " file. Retrying with uncompressed version." << endLog;
180 }
181 else
182 {
183 delete bz2_stream;
184 ini_file = uncompressed;
185 ini_file->seek (0, IO_SEEK_SET);
186 }
187 }
188 }
189
190 if (!ini_file)
191 {
192 /* Try to look for a plain .ini file because one of the following
193 happened above:
194 - there was no .bz2 file found on the mirror.
195 - the .bz2 file didn't look like a valid bzip2 file.
196 - there was an error during bzip2 decompression. */
197 current_ini_name = n->url + "/" + SETUP_INI_FILENAME;
198 ini_file = get_url_to_membuf (current_ini_name, owner);
199 }
200
201 if (!ini_file)
202 {
203 note (owner, IDS_SETUPINI_MISSING, SETUP_INI_FILENAME, n->url.c_str());
204 continue;
205 }
206
207 myFeedback.iniName (current_ini_name);
208 aBuilder.parse_mirror = n->url;
209 ini_init (ini_file, &aBuilder, myFeedback);
210
211 /*yydebug = 1; */
212
213 if (yyparse () || yyerror_count > 0)
214 myFeedback.error (yyerror_messages);
215 else
216 {
217 /* save known-good setup.ini locally */
218 const std::string fp = "file://" + local_dir + "/" +
219 rfc1738_escape_part (n->url) +
220 "/" + SETUP_INI_FILENAME;
221 io_stream::mkpath_p (PATH_TO_FILE, fp);
222 if (io_stream *out = io_stream::open (fp, "wb"))
223 {
224 ini_file->seek (0, IO_SEEK_SET);
225 if (io_stream::copy (ini_file, out) != 0)
226 io_stream::remove (fp);
227 delete out;
228 }
229 ++ini_count;
230 }
231 if (aBuilder.timestamp > setup_timestamp)
232 {
233 setup_timestamp = aBuilder.timestamp;
234 ini_setup_version = aBuilder.version;
235 }
236 delete ini_file;
237 }
238 return ini_count;
239 }
240
241 static bool
242 do_ini_thread (HINSTANCE h, HWND owner)
243 {
244 size_t ini_count = 0;
245 if (source == IDC_SOURCE_CWD)
246 ini_count = do_local_ini (owner);
247 else
248 ini_count = do_remote_ini (owner);
249
250 if (ini_count == 0)
251 return false;
252
253 if (get_root_dir ().c_str())
254 {
255 io_stream::mkpath_p (PATH_TO_DIR, "cygfile:///etc/setup");
256
257 unsigned int old_timestamp = 0;
258 io_stream *ots =
259 io_stream::open ("cygfile:///etc/setup/timestamp", "rt");
260 if (ots)
261 {
262 char temp[20];
263 memset (temp, '\0', 20);
264 if (ots->read (temp, 19))
265 sscanf (temp, "%u", &old_timestamp);
266 delete ots;
267 if (old_timestamp && setup_timestamp
268 && (old_timestamp > setup_timestamp))
269 {
270 int yn = yesno (owner, IDS_OLD_SETUPINI);
271 if (yn == IDNO)
272 LogSingleton::GetInstance().exit (1);
273 }
274 }
275 if (setup_timestamp)
276 {
277 io_stream *nts =
278 io_stream::open ("cygfile:///etc/setup/timestamp", "wt");
279 if (nts)
280 {
281 char temp[20];
282 sprintf (temp, "%u", setup_timestamp);
283 nts->write (temp, strlen (temp));
284 delete nts;
285 }
286 }
287 }
288
289 msg (".ini setup_version is %s, our setup_version is %s", ini_setup_version.size() ?
290 ini_setup_version.c_str() : "(null)",
291 setup_version);
292 if (ini_setup_version.size())
293 {
294 if (version_compare(setup_version, ini_setup_version) < 0)
295 note (owner, IDS_OLD_SETUP_VERSION, setup_version,
296 ini_setup_version.c_str());
297 }
298
299 return true;
300 }
301
302 static DWORD WINAPI
303 do_ini_thread_reflector(void* p)
304 {
305 HANDLE *context;
306 context = (HANDLE*)p;
307
308 try
309 {
310 bool succeeded = do_ini_thread((HINSTANCE)context[0], (HWND)context[1]);
311
312 // Tell the progress page that we're done downloading
313 Progress.PostMessage(WM_APP_SETUP_INI_DOWNLOAD_COMPLETE, 0, succeeded);
314 }
315 TOPLEVEL_CATCH("ini");
316
317 ExitThread(0);
318 }
319
320 static HANDLE context[2];
321
322 void
323 do_ini (HINSTANCE h, HWND owner)
324 {
325 context[0] = h;
326 context[1] = owner;
327
328 DWORD threadID;
329 CreateThread (NULL, 0, do_ini_thread_reflector, context, 0, &threadID);
330 }
331
This page took 0.051368 seconds and 5 git commands to generate.