Show deprecation warning for Windows versions 6.1 and 6.2
[cygwin-setup.git] / root.cc
blob1723a532b4961848e92bba4a72068195078c7d27
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", IDS_HELPTEXT_ROOT, 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 std::wstring title = LoadStringW(IDS_ROOT_BROWSE_TITLE);
103 wchar_t wname[MAX_PATH];
104 BROWSEINFOW bi;
105 memset (&bi, 0, sizeof (bi));
106 bi.hwndOwner = h;
107 bi.pszDisplayName = wname;
108 bi.lpszTitle = title.c_str();
109 bi.ulFlags = BIF_RETURNONLYFSDIRS;
110 bi.lpfn = browse_cb;
112 /* SHGetPathFromIDList doesn't handle path length > MAX_PATH. */
113 LPITEMIDLIST pidl;
114 pidl = SHBrowseForFolderW (&bi);
115 if (pidl)
117 CHAR name[MAX_PATH];
118 if (SHGetPathFromIDList (pidl, name))
119 eset (h, IDC_ROOT_DIR, name);
123 static int
124 directory_is_absolute ()
126 const std::string &r = get_root_dir ();
127 if (isalpha (r[0]) && r[1] == ':' && isdirsep (r[2]))
128 return 1;
129 return 0;
132 static int
133 directory_is_rootdir ()
135 const std::string &r = get_root_dir ();
136 size_t pos = r.find_first_of ("/\\");
137 if (pos != std::string::npos)
139 while (isdirsep (r[++pos]))
141 if (r[pos])
142 return 0;
144 return 1;
147 static int
148 directory_has_spaces ()
150 if (std::string(get_root_dir()).find(' ') != std::string::npos)
151 return 1;
152 return 0;
155 static int
156 directory_contains_wrong_version (HWND h)
158 HANDLE fh;
159 std::string cygwin_dll = get_root_dir() + "\\bin\\cygwin1.dll";
161 /* Check if we have a cygwin1.dll. If not, this is a new install.
162 If yes, check if the target machine type of this setup version is the
163 same as the machine type of the install Cygwin DLL. If yes, just go
164 ahead. If not, show a message and indicate this to the caller.
166 If anything goes wrong reading the header of cygwin1.dll, we check
167 cygcheck.exe's binary type. This also covers the situation that the
168 installed cygwin1.dll is broken for some reason. */
169 fh = CreateFileA (cygwin_dll.c_str (), GENERIC_READ, FILE_SHARE_VALID_FLAGS,
170 NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
171 if (fh != INVALID_HANDLE_VALUE)
173 DWORD read = 0;
174 struct {
175 LONG dos_header[32];
176 IMAGE_NT_HEADERS32 nt_header;
177 } hdr;
179 ReadFile (fh, &hdr, sizeof hdr, &read, NULL);
180 CloseHandle (fh);
181 if (read != sizeof hdr)
182 fh = INVALID_HANDLE_VALUE;
183 else
185 /* 32 bit setup and 32 bit inst? */
186 if (hdr.nt_header.FileHeader.Machine == IMAGE_FILE_MACHINE_I386
187 && !is_64bit)
188 return 0;
189 /* 64 bit setup and 64 bit inst? */
190 if (hdr.nt_header.FileHeader.Machine == IMAGE_FILE_MACHINE_AMD64
191 && is_64bit)
192 return 0;
195 if (fh == INVALID_HANDLE_VALUE)
197 DWORD type;
198 std::string cygcheck_exe = get_root_dir() + "\\bin\\cygcheck.exe";
200 /* Probably new installation */
201 if (!GetBinaryType (cygcheck_exe.c_str (), &type))
203 is_new_install = true;
204 return 0;
206 /* 64 bit setup and 64 bit inst? */
207 if (type == SCS_32BIT_BINARY && !is_64bit)
208 return 0;
209 /* 32 bit setup and 32 bit inst? */
210 if (type == SCS_64BIT_BINARY && is_64bit)
211 return 0;
214 /* Forestall mixing. */
215 const char *setup_ver = is_64bit ? "64" : "32";
216 const char *inst_ver = is_64bit ? "32" : "64";
217 mbox (h, IDS_MIXED_BITNESS_ERROR, MB_OK,
218 setup_ver, inst_ver, is_64bit ? "x86" : "x86_64", inst_ver, setup_ver);
219 return 1;
222 bool
223 RootPage::OnMessageCmd (int id, HWND hwndctl, UINT code)
225 switch (id)
228 case IDC_ROOT_DIR:
229 case IDC_ROOT_SYSTEM:
230 case IDC_ROOT_USER:
231 check_if_enable_next (GetHWND ());
232 break;
234 case IDC_ROOT_BROWSE:
235 browse (GetHWND ());
236 break;
237 default:
238 return false;
240 return true;
243 RootPage::RootPage ()
245 sizeProcessor.AddControlInfo (RootControlsInfo);
248 bool
249 RootPage::Create ()
251 return PropertyPage::Create (IDD_ROOT);
254 void
255 RootPage::OnInit ()
257 if (((std::string)RootOption).size())
258 set_root_dir((std::string)RootOption);
259 if (!get_root_dir ().size())
260 read_mounts (std::string ());
261 orig_root_dir = get_root_dir();
262 load_dialog (GetHWND ());
265 void
266 RootPage::OnActivate ()
268 check_if_enable_next (GetHWND ());
271 bool
272 RootPage::wantsActivation() const
274 return (source != IDC_SOURCE_DOWNLOAD);
277 long
278 RootPage::OnNext ()
280 HWND h = GetHWND ();
282 save_dialog (h);
284 if (!directory_is_absolute ())
286 note (h, IDS_ROOT_ABSOLUTE);
287 return -1;
289 else if (get_root_dir() != orig_root_dir &&
290 directory_is_rootdir () && (IDNO == yesno (h, IDS_ROOT_SLASH)))
291 return -1;
292 else if (directory_has_spaces () && (IDNO == yesno (h, IDS_ROOT_SPACE)))
293 return -1;
294 else if (directory_contains_wrong_version (h))
295 return -1;
297 Log (LOG_PLAIN) << "root: " << get_root_dir ()
298 << (root_scope == IDC_ROOT_USER ? " user" : " system") << endLog;
300 return 0;
303 long
304 RootPage::OnBack ()
306 HWND h = GetHWND ();
308 save_dialog (h);
309 return 0;
312 long
313 RootPage::OnUnattended ()
315 return OnNext();