~ubuntu-branches/ubuntu/utopic/gdisk/utopic-proposed

« back to all changes in this revision

Viewing changes to .pc/bug-1285197.diff/support.cc

  • Committer: Package Import Robot
  • Author(s): William Grant
  • Date: 2015-06-19 19:34:36 UTC
  • Revision ID: package-import@ubuntu.com-20150619193436-qn21m9h5xec9j5gn
Tags: 0.8.8-1ubuntu0.1
debian/patches/bug-1285197.diff: Don't leave suffix uninitialised when
none was passed to IeeeToInt. Fixes incorrect partition boundaries and
other failures on ppc64el and possibly other architectures. (LP: #1285197)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// support.cc
 
2
// Non-class support functions for gdisk program.
 
3
// Primarily by Rod Smith, February 2009, but with a few functions
 
4
// copied from other sources (see attributions below).
 
5
 
 
6
/* This program is copyright (c) 2009-2013 by Roderick W. Smith. It is distributed
 
7
  under the terms of the GNU GPL version 2, as detailed in the COPYING file. */
 
8
 
 
9
#define __STDC_LIMIT_MACROS
 
10
#define __STDC_CONSTANT_MACROS
 
11
 
 
12
#include <stdio.h>
 
13
#include <stdint.h>
 
14
#include <errno.h>
 
15
#include <fcntl.h>
 
16
#include <string.h>
 
17
#include <sys/stat.h>
 
18
#include <string>
 
19
#include <iostream>
 
20
#include <sstream>
 
21
#include "support.h"
 
22
 
 
23
#include <sys/types.h>
 
24
 
 
25
// As of 1/2010, BLKPBSZGET is very new, so I'm explicitly defining it if
 
26
// it's not already defined. This should become unnecessary in the future.
 
27
// Note that this is a Linux-only ioctl....
 
28
#ifndef BLKPBSZGET
 
29
#define BLKPBSZGET _IO(0x12,123)
 
30
#endif
 
31
 
 
32
using namespace std;
 
33
 
 
34
// Reads a string from stdin, returning it as a C++-style string.
 
35
// Note that the returned string will NOT include the carriage return
 
36
// entered by the user.
 
37
string ReadString(void) {
 
38
   string inString;
 
39
 
 
40
   getline(cin, inString);
 
41
   if (!cin.good())
 
42
      exit(5);
 
43
   return inString;
 
44
} // ReadString()
 
45
 
 
46
// Get a numeric value from the user, between low and high (inclusive).
 
47
// Keeps looping until the user enters a value within that range.
 
48
// If user provides no input, def (default value) is returned.
 
49
// (If def is outside of the low-high range, an explicit response
 
50
// is required.)
 
51
int GetNumber(int low, int high, int def, const string & prompt) {
 
52
   int response, num;
 
53
   char line[255];
 
54
 
 
55
   if (low != high) { // bother only if low and high differ...
 
56
      do {
 
57
         cout << prompt;
 
58
         cin.getline(line, 255);
 
59
         if (!cin.good())
 
60
            exit(5);
 
61
         num = sscanf(line, "%d", &response);
 
62
         if (num == 1) { // user provided a response
 
63
            if ((response < low) || (response > high))
 
64
               cout << "Value out of range\n";
 
65
         } else { // user hit enter; return default
 
66
            response = def;
 
67
         } // if/else
 
68
      } while ((response < low) || (response > high));
 
69
   } else { // low == high, so return this value
 
70
      cout << "Using " << low << "\n";
 
71
      response = low;
 
72
   } // else
 
73
   return (response);
 
74
} // GetNumber()
 
75
 
 
76
// Gets a Y/N response (and converts lowercase to uppercase)
 
77
char GetYN(void) {
 
78
   char response;
 
79
   string line;
 
80
 
 
81
   do {
 
82
      cout << "(Y/N): ";
 
83
      line = ReadString();
 
84
      response = toupper(line[0]);
 
85
   } while ((response != 'Y') && (response != 'N'));
 
86
   return response;
 
87
} // GetYN(void)
 
88
 
 
89
// Obtains a sector number, between low and high, from the
 
90
// user, accepting values prefixed by "+" to add sectors to low,
 
91
// or the same with "K", "M", "G", "T", or "P" as suffixes to add
 
92
// kilobytes, megabytes, gigabytes, terabytes, or petabytes,
 
93
// respectively. If a "-" prefix is used, use the high value minus
 
94
// the user-specified number of sectors (or KiB, MiB, etc.). Use the
 
95
// def value as the default if the user just hits Enter. The sSize is
 
96
// the sector size of the device.
 
97
uint64_t GetSectorNum(uint64_t low, uint64_t high, uint64_t def, uint64_t sSize,
 
98
                      const string & prompt) {
 
99
   uint64_t response;
 
100
   char line[255];
 
101
 
 
102
   do {
 
103
      cout << prompt;
 
104
      cin.getline(line, 255);
 
105
      if (!cin.good())
 
106
         exit(5);
 
107
      response = IeeeToInt(line, sSize, low, high, def);
 
108
   } while ((response < low) || (response > high));
 
109
   return response;
 
110
} // GetSectorNum()
 
111
 
 
112
// Convert an IEEE-1541-2002 value (K, M, G, T, P, or E) to its equivalent in
 
113
// number of sectors. If no units are appended, interprets as the number
 
114
// of sectors; otherwise, interprets as number of specified units and
 
115
// converts to sectors. For instance, with 512-byte sectors, "1K" converts
 
116
// to 2. If value includes a "+", adds low and subtracts 1; if SIValue
 
117
// inclues a "-", subtracts from high. If IeeeValue is empty, returns def.
 
118
// Returns final sector value. In case inValue is invalid, returns 0 (a
 
119
// sector value that's always in use on GPT and therefore invalid); and if
 
120
// inValue works out to something outside the range low-high, returns the
 
121
// computed value; the calling function is responsible for checking the
 
122
// validity of this value.
 
123
// NOTE: There's a difference in how GCC and VC++ treat oversized values
 
124
// (say, "999999999999999999999") read via the ">>" operator; GCC turns
 
125
// them into the maximum value for the type, whereas VC++ turns them into
 
126
// 0 values. The result is that IeeeToInt() returns UINT64_MAX when
 
127
// compiled with GCC (and so the value is rejected), whereas when VC++
 
128
// is used, the default value is returned.
 
129
uint64_t IeeeToInt(string inValue, uint64_t sSize, uint64_t low, uint64_t high, uint64_t def) {
 
130
   uint64_t response = def, bytesPerUnit = 1, mult = 1, divide = 1;
 
131
   size_t foundAt = 0;
 
132
   char suffix, plusFlag = ' ';
 
133
   string suffixes = "KMGTPE";
 
134
   int badInput = 0; // flag bad input; once this goes to 1, other values are irrelevant
 
135
 
 
136
   if (sSize == 0) {
 
137
      sSize = SECTOR_SIZE;
 
138
      cerr << "Bug: Sector size invalid in SIToInt()!\n";
 
139
   } // if
 
140
 
 
141
   // Remove leading spaces, if present
 
142
   while (inValue[0] == ' ')
 
143
      inValue.erase(0, 1);
 
144
 
 
145
   // If present, flag and remove leading plus or minus sign
 
146
   if ((inValue[0] == '+') || (inValue[0] == '-')) {
 
147
      plusFlag = inValue[0];
 
148
      inValue.erase(0, 1);
 
149
   } // if
 
150
 
 
151
   // Extract numeric response and, if present, suffix
 
152
   istringstream inString(inValue);
 
153
   if (((inString.peek() < '0') || (inString.peek() > '9')) && (inString.peek() != -1))
 
154
      badInput = 1;
 
155
   inString >> response >> suffix;
 
156
   suffix = toupper(suffix);
 
157
 
 
158
   // If no response, or if response == 0, use default (def)
 
159
   if ((inValue.length() == 0) || (response == 0)) {
 
160
      response = def;
 
161
      suffix = ' ';
 
162
      plusFlag = ' ';
 
163
   } // if
 
164
 
 
165
   // Find multiplication and division factors for the suffix
 
166
   foundAt = suffixes.find(suffix);
 
167
   if (foundAt != string::npos) {
 
168
      bytesPerUnit = UINT64_C(1) << (10 * (foundAt + 1));
 
169
      mult = bytesPerUnit / sSize;
 
170
      divide = sSize / bytesPerUnit;
 
171
   } // if
 
172
 
 
173
   // Adjust response based on multiplier and plus flag, if present
 
174
   if (mult > 1) {
 
175
      if (response > (UINT64_MAX / mult))
 
176
         badInput = 1;
 
177
      else
 
178
         response *= mult;
 
179
   } else if (divide > 1) {
 
180
         response /= divide;
 
181
   } // if/elseif
 
182
 
 
183
   if (plusFlag == '+') {
 
184
      // Recompute response based on low part of range (if default == high
 
185
      // value, which should be the case when prompting for the end of a
 
186
      // range) or the defaut value (if default != high, which should be
 
187
      // the case for the first sector of a partition).
 
188
      if (def == high) {
 
189
         if (response > 0)
 
190
            response--;
 
191
         if (response > (UINT64_MAX - low))
 
192
            badInput = 1;
 
193
         else
 
194
            response = response + low;
 
195
      } else {
 
196
         if (response > (UINT64_MAX - def))
 
197
            badInput = 1;
 
198
         else
 
199
            response = response + def;
 
200
      } // if/else
 
201
   } else if (plusFlag == '-') {
 
202
      if (response > high)
 
203
         badInput = 1;
 
204
      else
 
205
         response = high - response;
 
206
   } // if   
 
207
 
 
208
   if (badInput)
 
209
      response = UINT64_C(0);
 
210
 
 
211
   return response;
 
212
} // IeeeToInt()
 
213
 
 
214
// Takes a size and converts this to a size in IEEE-1541-2002 units (KiB, MiB,
 
215
// GiB, TiB, PiB, or EiB), returned in C++ string form. The size is either in
 
216
// units of the sector size or, if that parameter is omitted, in bytes.
 
217
// (sectorSize defaults to 1).
 
218
string BytesToIeee(uint64_t size, uint32_t sectorSize) {
 
219
   float sizeInIeee;
 
220
   unsigned int index = 0;
 
221
   string units, prefixes = " KMGTPEZ";
 
222
   ostringstream theValue;
 
223
 
 
224
   sizeInIeee = size * (float) sectorSize;
 
225
   while ((sizeInIeee > 1024.0) && (index < (prefixes.length() - 1))) {
 
226
      index++;
 
227
      sizeInIeee /= 1024.0;
 
228
   } // while
 
229
   theValue.setf(ios::fixed);
 
230
   if (prefixes[index] == ' ') {
 
231
      units = " bytes";
 
232
      theValue.precision(0);
 
233
   } else {
 
234
      units = "  iB";
 
235
      units[1] = prefixes[index];
 
236
      theValue.precision(1);
 
237
   } // if/else
 
238
   theValue << sizeInIeee << units;
 
239
   return theValue.str();
 
240
} // BlocksToIeee()
 
241
 
 
242
// Converts two consecutive characters in the input string into a
 
243
// number, interpreting the string as a hexadecimal number, starting
 
244
// at the specified position.
 
245
unsigned char StrToHex(const string & input, unsigned int position) {
 
246
   unsigned char retval = 0x00;
 
247
   unsigned int temp;
 
248
 
 
249
   if (input.length() > position) {
 
250
      sscanf(input.substr(position, 2).c_str(), "%x", &temp);
 
251
      retval = (unsigned char) temp;
 
252
   } // if
 
253
   return retval;
 
254
} // StrToHex()
 
255
 
 
256
// Returns 1 if input can be interpreted as a hexadecimal number --
 
257
// all characters must be spaces, digits, or letters A-F (upper- or
 
258
// lower-case), with at least one valid hexadecimal digit; with the
 
259
// exception of the first two characters, which may be "0x"; otherwise
 
260
// returns 0.
 
261
int IsHex(string input) {
 
262
   int isHex = 1, foundHex = 0, i;
 
263
 
 
264
   if (input.substr(0, 2) == "0x")
 
265
      input.erase(0, 2);
 
266
   for (i = 0; i < (int) input.length(); i++) {
 
267
      if ((input[i] < '0') || (input[i] > '9')) {
 
268
         if ((input[i] < 'A') || (input[i] > 'F')) {
 
269
            if ((input[i] < 'a') || (input[i] > 'f')) {
 
270
               if ((input[i] != ' ') && (input[i] != '\n')) {
 
271
                  isHex = 0;
 
272
               }
 
273
            } else foundHex = 1;
 
274
         } else foundHex = 1;
 
275
      } else foundHex = 1;
 
276
   } // for
 
277
   if (!foundHex)
 
278
      isHex = 0;
 
279
   return isHex;
 
280
} // IsHex()
 
281
 
 
282
// Return 1 if the CPU architecture is little endian, 0 if it's big endian....
 
283
int IsLittleEndian(void) {
 
284
   int littleE = 1; // assume little-endian (Intel-style)
 
285
   union {
 
286
      uint32_t num;
 
287
      unsigned char uc[sizeof(uint32_t)];
 
288
   } endian;
 
289
 
 
290
   endian.num = 1;
 
291
   if (endian.uc[0] != (unsigned char) 1) {
 
292
      littleE = 0;
 
293
   } // if
 
294
   return (littleE);
 
295
} // IsLittleEndian()
 
296
 
 
297
// Reverse the byte order of theValue; numBytes is number of bytes
 
298
void ReverseBytes(void* theValue, int numBytes) {
 
299
   char* tempValue = NULL;
 
300
   int i;
 
301
 
 
302
   tempValue = new char [numBytes];
 
303
   if (tempValue != NULL) {
 
304
      memcpy(tempValue, theValue, numBytes);
 
305
      for (i = 0; i < numBytes; i++)
 
306
         ((char*) theValue)[i] = tempValue[numBytes - i - 1];
 
307
      delete[] tempValue;
 
308
   } else {
 
309
      cerr << "Could not allocate memory in ReverseBytes()! Terminating\n";
 
310
      exit(1);
 
311
   } // if/else
 
312
} // ReverseBytes()
 
313
 
 
314
// On Windows, display a warning and ask whether to continue. If the user elects
 
315
// not to continue, exit immediately.
 
316
void WinWarning(void) {
 
317
   #ifdef _WIN32
 
318
   cout << "\a************************************************************************\n"
 
319
   << "Most versions of Windows cannot boot from a GPT disk, and most varieties\n"
 
320
   << "prior to Vista cannot read GPT disks. Therefore, you should exit now\n"
 
321
   << "unless you understand the implications of converting MBR to GPT or creating\n"
 
322
   << "a new GPT disk layout!\n"
 
323
   << "************************************************************************\n\n";
 
324
   cout << "Are you SURE you want to continue? ";
 
325
   if (GetYN() != 'Y')
 
326
      exit(0);
 
327
   #endif
 
328
} // WinWarning()