Translated using Weblate (Chinese (Simplified))
[cygwin-setup.git] / root.cc
blobccbd6ae309a56b7251cdec9df9917fb2997f1d97
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();
263 if (!nt_sec.isRunAsAdmin())
265 // disable IDC_ROOT_SYSTEM if not running as admin
266 EnableWindow(GetDlgItem(IDC_ROOT_SYSTEM), FALSE);
267 root_scope = IDC_ROOT_USER;
269 else
271 set_default_root_scope();
274 load_dialog (GetHWND ());
277 void
278 RootPage::OnActivate ()
280 check_if_enable_next (GetHWND ());
283 bool
284 RootPage::wantsActivation() const
286 return (source != IDC_SOURCE_DOWNLOAD);
289 long
290 RootPage::OnNext ()
292 HWND h = GetHWND ();
294 save_dialog (h);
296 if (!directory_is_absolute ())
298 note (h, IDS_ROOT_ABSOLUTE);
299 return -1;
301 else if (get_root_dir() != orig_root_dir &&
302 directory_is_rootdir () && (IDNO == yesno (h, IDS_ROOT_SLASH)))
303 return -1;
304 else if (directory_has_spaces () && (IDNO == yesno (h, IDS_ROOT_SPACE)))
305 return -1;
306 else if (directory_contains_wrong_version (h))
307 return -1;
309 Log (LOG_PLAIN) << "root: " << get_root_dir ()
310 << (root_scope == IDC_ROOT_USER ? " user" : " system") << endLog;
312 if (root_scope == IDC_ROOT_SYSTEM)
313 nt_sec.setAdminGroup ();
314 else
315 nt_sec.resetPrimaryGroup ();
317 return 0;
320 long
321 RootPage::OnBack ()
323 HWND h = GetHWND ();
325 save_dialog (h);
326 return 0;
329 long
330 RootPage::OnUnattended ()
332 return OnNext();