Fix format() returning a std::string containing a terminating null
[cygwin-setup.git] / root.cc
blob6fc25b9ebce6489cf095704dca63199eb70cf980
1 /*
2 * Copyright (c) 2000, Red Hat, Inc.
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.
9 * A copy of the GNU General Public License can be found at
10 * http://www.gnu.org/
12 * Written by DJ Delorie <dj@cygnus.com>
16 /* The purpose of this file is to ask the user where they want the
17 root of the installation to be, and to ask whether the user prefers
18 text or binary mounts. */
20 #include "root.h"
22 #include "LogSingleton.h"
24 #include "win32.h"
25 #include <shlobj.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <ctype.h>
30 #include "ini.h"
31 #include "dialog.h"
32 #include "resource.h"
33 #include "state.h"
34 #include "msg.h"
35 #include "package_db.h"
36 #include "mount.h"
37 #include "propsheet.h"
39 #include "getopt++/StringOption.h"
41 StringOption RootOption ("", 'R', "root", "Root installation directory", false);
43 static ControlAdjuster::ControlInfo RootControlsInfo[] = {
44 { IDC_ROOTDIR_GRP, CP_STRETCH, CP_TOP },
45 { IDC_ROOT_DIR, CP_STRETCH, CP_TOP },
46 { IDC_ROOT_BROWSE, CP_RIGHT, CP_TOP },
48 { IDC_INSTALLFOR_GRP, CP_STRETCH, CP_STRETCH },
49 { IDC_ROOT_SYSTEM, CP_LEFT, CP_TOP },
50 { IDC_ALLUSERS_TEXT, CP_STRETCH, CP_TOP },
51 { IDC_ROOT_USER, CP_LEFT, CP_BOTTOM },
52 { IDC_JUSTME_TEXT, CP_STRETCH, CP_BOTTOM },
54 {0, CP_LEFT, CP_TOP}
57 static int su[] = { IDC_ROOT_SYSTEM, IDC_ROOT_USER, 0 };
59 static std::string orig_root_dir;
61 void
62 RootPage::check_if_enable_next (HWND h)
64 DWORD ButtonFlags = PSWIZB_BACK;
65 // if there's something in the root dir box, and we have a scope, enable next
66 if (egetString (h, IDC_ROOT_DIR).size() && root_scope)
67 ButtonFlags |= PSWIZB_NEXT;
68 GetOwner ()->SetButtons (ButtonFlags);
71 static void
72 load_dialog (HWND h)
74 rbset (h, su, root_scope);
75 eset (h, IDC_ROOT_DIR, get_root_dir ());
78 static void
79 save_dialog (HWND h)
81 root_scope = rbget (h, su);
82 set_root_dir (egetString (h, IDC_ROOT_DIR));
85 static int CALLBACK
86 browse_cb (HWND h, UINT msg, LPARAM lp, LPARAM data)
88 switch (msg)
90 case BFFM_INITIALIZED:
91 if (get_root_dir ().size())
92 SendMessage (h, BFFM_SETSELECTION, TRUE, (LPARAM) get_root_dir ().c_str());
93 break;
95 return 0;
98 static void
99 browse (HWND h)
101 BROWSEINFO bi;
102 /* SHGetPathFromIDList doesn't handle path length > MAX_PATH. */
103 CHAR name[MAX_PATH];
104 LPITEMIDLIST pidl;
105 memset (&bi, 0, sizeof (bi));
106 bi.hwndOwner = h;
107 bi.pszDisplayName = name;
108 bi.lpszTitle = "Select an installation root directory";
109 bi.ulFlags = BIF_RETURNONLYFSDIRS;
110 bi.lpfn = browse_cb;
111 pidl = SHBrowseForFolder (&bi);
112 if (pidl)
114 if (SHGetPathFromIDList (pidl, name))
115 eset (h, IDC_ROOT_DIR, name);
119 static int
120 directory_is_absolute ()
122 const std::string &r = get_root_dir ();
123 if (isalpha (r[0]) && r[1] == ':' && isdirsep (r[2]))
124 return 1;
125 return 0;
128 static int
129 directory_is_rootdir ()
131 const std::string &r = get_root_dir ();
132 size_t pos = r.find_first_of ("/\\");
133 if (pos != std::string::npos)
135 while (isdirsep (r[++pos]))
137 if (r[pos])
138 return 0;
140 return 1;
143 static int
144 directory_has_spaces ()
146 if (std::string(get_root_dir()).find(' ') != std::string::npos)
147 return 1;
148 return 0;
151 static int
152 directory_contains_wrong_version (HWND h)
154 HANDLE fh;
155 std::string cygwin_dll = get_root_dir() + "\\bin\\cygwin1.dll";
157 /* Check if we have a cygwin1.dll. If not, this is a new install.
158 If yes, check if the target machine type of this setup version is the
159 same as the machine type of the install Cygwin DLL. If yes, just go
160 ahead. If not, show a message and indicate this to the caller.
162 If anything goes wrong reading the header of cygwin1.dll, we check
163 cygcheck.exe's binary type. This also covers the situation that the
164 installed cygwin1.dll is broken for some reason. */
165 fh = CreateFileA (cygwin_dll.c_str (), GENERIC_READ, FILE_SHARE_VALID_FLAGS,
166 NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
167 if (fh != INVALID_HANDLE_VALUE)
169 DWORD read = 0;
170 struct {
171 LONG dos_header[32];
172 IMAGE_NT_HEADERS32 nt_header;
173 } hdr;
175 ReadFile (fh, &hdr, sizeof hdr, &read, NULL);
176 CloseHandle (fh);
177 if (read != sizeof hdr)
178 fh = INVALID_HANDLE_VALUE;
179 else
181 /* 32 bit setup and 32 bit inst? */
182 if (hdr.nt_header.FileHeader.Machine == IMAGE_FILE_MACHINE_I386
183 && !is_64bit)
184 return 0;
185 /* 64 bit setup and 64 bit inst? */
186 if (hdr.nt_header.FileHeader.Machine == IMAGE_FILE_MACHINE_AMD64
187 && is_64bit)
188 return 0;
191 if (fh == INVALID_HANDLE_VALUE)
193 DWORD type;
194 std::string cygcheck_exe = get_root_dir() + "\\bin\\cygcheck.exe";
196 /* Probably new installation */
197 if (!GetBinaryType (cygcheck_exe.c_str (), &type))
199 is_new_install = true;
200 return 0;
202 /* 64 bit setup and 64 bit inst? */
203 if (type == SCS_32BIT_BINARY && !is_64bit)
204 return 0;
205 /* 32 bit setup and 32 bit inst? */
206 if (type == SCS_64BIT_BINARY && is_64bit)
207 return 0;
210 /* Forestall mixing. */
211 const char *setup_ver = is_64bit ? "64" : "32";
212 const char *inst_ver = is_64bit ? "32" : "64";
213 mbox (h, IDS_MIXED_BITNESS_ERROR, MB_OK,
214 setup_ver, inst_ver, is_64bit ? "x86" : "x86_64", inst_ver, setup_ver);
215 return 1;
218 bool
219 RootPage::OnMessageCmd (int id, HWND hwndctl, UINT code)
221 switch (id)
224 case IDC_ROOT_DIR:
225 case IDC_ROOT_SYSTEM:
226 case IDC_ROOT_USER:
227 check_if_enable_next (GetHWND ());
228 break;
230 case IDC_ROOT_BROWSE:
231 browse (GetHWND ());
232 break;
233 default:
234 return false;
236 return true;
239 RootPage::RootPage ()
241 sizeProcessor.AddControlInfo (RootControlsInfo);
244 bool
245 RootPage::Create ()
247 return PropertyPage::Create (IDD_ROOT);
250 void
251 RootPage::OnInit ()
253 if (((std::string)RootOption).size())
254 set_root_dir((std::string)RootOption);
255 if (!get_root_dir ().size())
256 read_mounts (std::string ());
257 orig_root_dir = get_root_dir();
258 load_dialog (GetHWND ());
261 void
262 RootPage::OnActivate ()
264 check_if_enable_next (GetHWND ());
267 bool
268 RootPage::wantsActivation() const
270 return (source != IDC_SOURCE_DOWNLOAD);
273 long
274 RootPage::OnNext ()
276 HWND h = GetHWND ();
278 save_dialog (h);
280 if (!directory_is_absolute ())
282 note (h, IDS_ROOT_ABSOLUTE);
283 return -1;
285 else if (get_root_dir() != orig_root_dir &&
286 directory_is_rootdir () && (IDNO == yesno (h, IDS_ROOT_SLASH)))
287 return -1;
288 else if (directory_has_spaces () && (IDNO == yesno (h, IDS_ROOT_SPACE)))
289 return -1;
290 else if (directory_contains_wrong_version (h))
291 return -1;
293 Log (LOG_PLAIN) << "root: " << get_root_dir ()
294 << (root_scope == IDC_ROOT_USER ? " user" : " system") << endLog;
296 return 0;
299 long
300 RootPage::OnBack ()
302 HWND h = GetHWND ();
304 save_dialog (h);
305 return 0;
308 long
309 RootPage::OnUnattended ()
311 return OnNext();