| // attributes.cc |
| // Class to manage partition attribute codes. These are binary bit fields, |
| // of which only four are currently (2/2011) documented on Wikipedia, and |
| // two others found from other sources. |
| |
| /* This program is copyright (c) 2009-2013 by Roderick W. Smith. It is distributed |
| under the terms of the GNU GPL version 2, as detailed in the COPYING file. */ |
| |
| #define __STDC_LIMIT_MACROS |
| #ifndef __STDC_CONSTANT_MACROS |
| #define __STDC_CONSTANT_MACROS |
| #endif |
| |
| #include <stdint.h> |
| #include <stdio.h> |
| #include <iostream> |
| #include <sstream> |
| |
| #include "attributes.h" |
| #include "support.h" |
| |
| using namespace std; |
| |
| string Attributes::atNames[NUM_ATR]; |
| int Attributes::numAttrs = 0; |
| //Attributes::staticInit Attributes::staticInitializer; |
| |
| // Default constructor |
| Attributes::Attributes(void) { |
| numAttrs++; |
| if (numAttrs == 1) |
| Setup(); |
| attributes = 0; |
| } // constructor |
| |
| // Alternate constructor |
| Attributes::Attributes(const uint64_t a) { |
| numAttrs++; |
| if (numAttrs == 1) |
| Setup(); |
| attributes = a; |
| } // alternate constructor |
| |
| // Destructor. |
| Attributes::~Attributes(void) { |
| numAttrs--; |
| } // Attributes destructor |
| |
| void Attributes::Setup(void) { |
| ostringstream temp; |
| |
| // Most bits are undefined, so start by giving them an |
| // appropriate name |
| for (int i = 0; i < NUM_ATR; i++) { |
| temp.str(""); |
| temp << "Undefined bit #" << i; |
| Attributes::atNames[i] = temp.str(); |
| } // for |
| |
| // Now reset those names that are defined.... |
| atNames[0] = "system partition"; // required for computer to operate |
| atNames[1] = "hide from EFI"; |
| atNames[2] = "legacy BIOS bootable"; |
| atNames[60] = "read-only"; |
| atNames[62] = "hidden"; |
| atNames[63] = "do not automount"; |
| } // Attributes::Setup() |
| |
| // Display current attributes to user |
| void Attributes::DisplayAttributes(void) { |
| uint32_t i; |
| int numSet = 0; |
| |
| cout << "Attribute value is "; |
| cout.setf(ios::uppercase); |
| cout.fill('0'); |
| cout.width(16); |
| cout << hex << attributes << dec << ". Set fields are:\n"; |
| for (i = 0; i < NUM_ATR; i++) { |
| if ((UINT64_C(1) << i) & attributes) { |
| cout << i << " (" << GetAttributeName(i) << ")" << "\n"; |
| numSet++; |
| } // if |
| } // for |
| cout.fill(' '); |
| if (numSet == 0) |
| cout << " No fields set\n"; |
| cout << "\n"; |
| } // Attributes::DisplayAttributes() |
| |
| // Display attributes for a partition. Note that partNum is just passed for |
| // immediate display; it's not used to access a particular partition. |
| void Attributes::ShowAttributes(const uint32_t partNum) { |
| uint32_t bitNum; |
| bool bitset; |
| |
| for (bitNum = 0; bitNum < 64; bitNum++) { |
| bitset = (UINT64_C(1) << bitNum) & attributes; |
| if (bitset) { |
| cout << partNum+1 << ":" << bitNum << ":" << bitset |
| << " (" << GetAttributeName(bitNum) << ")" << endl; |
| } // if |
| } // for |
| } // Attributes::ShowAttributes |
| |
| // Prompt user for attribute changes |
| void Attributes::ChangeAttributes(void) { |
| int response; |
| uint64_t bitValue; |
| |
| cout << "Known attributes are:\n"; |
| ListAttributes(); |
| cout << "\n"; |
| |
| do { |
| DisplayAttributes(); |
| response = GetNumber(0, NUM_ATR, 64, |
| "Toggle which attribute field (0-63, 64 or <Enter> to exit): "); |
| if (response != 64) { |
| bitValue = UINT64_C(1) << response; // Find the integer value of the bit |
| if (bitValue & attributes) { // bit is set |
| attributes &= ~bitValue; // so unset it |
| cout << "Have disabled the '" << atNames[response] << "' attribute.\n"; |
| } else { // bit is not set |
| attributes |= bitValue; // so set it |
| cout << "Have enabled the '" << atNames[response] << "' attribute.\n"; |
| } // if/else |
| } // if |
| } while (response != 64); |
| } // Attributes::ChangeAttributes() |
| |
| // Display all defined attributes on the screen (omits undefined bits). |
| void Attributes::ListAttributes(void) { |
| uint32_t bitNum; |
| string tempAttr; |
| |
| for (bitNum = 0; bitNum < NUM_ATR; bitNum++) { |
| tempAttr = GetAttributeName(bitNum); |
| if (tempAttr.substr(0, 15) != "Undefined bit #" ) |
| cout << bitNum << ": " << Attributes::GetAttributeName(bitNum) << "\n"; |
| } // for |
| } // Attributes::ListAttributes |
| |
| // multifaceted attributes access |
| // returns true upon success, false upon failure |
| bool Attributes::OperateOnAttributes(const uint32_t partNum, const string& attributeOperator, const string& attributeBits) { |
| |
| // attribute access opcode |
| typedef enum { |
| ao_or, ao_nand, ao_xor, ao_assignall, // operate on all attributes (bitmask) |
| ao_unknown, // must be after bitmask operators and before bitnum operators |
| ao_set, ao_clear, ao_toggle, ao_get // operate on a single attribute (bitnum) |
| } attribute_opcode_t; // typedef enum |
| |
| // translate attribute operator into an attribute opcode |
| attribute_opcode_t attributeOpcode = ao_unknown; { // opcode is not known yet |
| if (attributeOperator == "or") attributeOpcode = ao_or; |
| else if (attributeOperator == "nand") attributeOpcode = ao_nand; |
| else if (attributeOperator == "xor") attributeOpcode = ao_xor; |
| else if (attributeOperator == "=") attributeOpcode = ao_assignall; |
| else if (attributeOperator == "set") attributeOpcode = ao_set; |
| else if (attributeOperator == "clear") attributeOpcode = ao_clear; |
| else if (attributeOperator == "toggle") attributeOpcode = ao_toggle; |
| else if (attributeOperator == "get") attributeOpcode = ao_get; |
| else { |
| cerr << "Unknown attributes operator: " << attributeOperator << endl; |
| return false; |
| } // else |
| } // attributeOpcode |
| |
| // get bit mask if operating on entire attribute set |
| uint64_t attributeBitMask; { if (attributeOpcode < ao_unknown) { |
| if (1 != sscanf (attributeBits.c_str(), "%qx", (long long unsigned int*) &attributeBitMask)) { |
| cerr << "Could not convert hex attribute mask" << endl; |
| return false; |
| } // if |
| }} // attributeBitMask, if |
| |
| // get bit number and calculate bit mask if operating on a single attribute |
| int bitNum; { if (attributeOpcode > ao_unknown) { |
| if (1 != sscanf (attributeBits.c_str(), "%d", &bitNum)) { |
| cerr << "Could not convert bit number" << endl; |
| return false; |
| } // if |
| const uint64_t one = 1; |
| attributeBitMask = one << bitNum; |
| }} // bitNum, if |
| |
| switch (attributeOpcode) { |
| // assign all attributes at once |
| case ao_assignall: attributes = attributeBitMask; break; |
| |
| // set individual attribute(s) |
| case ao_set: |
| case ao_or: attributes |= attributeBitMask; break; |
| |
| // clear individual attribute(s) |
| case ao_clear: |
| case ao_nand: attributes &= ~attributeBitMask; break; |
| |
| // toggle individual attribute(s) |
| case ao_toggle: |
| case ao_xor: attributes ^= attributeBitMask; break; |
| |
| // display a single attribute |
| case ao_get: { |
| cout << partNum+1 << ":" << bitNum << ":" |
| << bool (attributeBitMask & attributes) << endl; |
| break; |
| } // case ao_get |
| |
| default: break; // will never get here |
| } // switch |
| |
| return true; |
| } // Attributes::OperateOnAttributes() |
| |
| /******************************* |
| * * |
| * Non-class support functions * |
| * * |
| *******************************/ |
| |
| // Display attributes |
| ostream & operator<<(ostream & os, const Attributes & data) { |
| os << data.GetAttributes(); |
| return os; |
| } // operator<<() |