right_popen 1.0.5-x86-mswin32-60 → 1.0.6-x86-mswin32-60

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1144,7 +1144,7 @@ static VALUE right_popen_get_current_user_environment(VALUE vSelf)
1144
1144
  }
1145
1145
  }
1146
1146
 
1147
- // merge environment.
1147
+ // convert environment block to a Ruby string.
1148
1148
  //
1149
1149
  // note that there is only a unicode form of this API call (instead of
1150
1150
  // the usual _A and _W pair) and that the environment strings appear to
@@ -1166,6 +1166,268 @@ static VALUE right_popen_get_current_user_environment(VALUE vSelf)
1166
1166
  }
1167
1167
  }
1168
1168
 
1169
+ // Summary:
1170
+ // grows the environment block as needed.
1171
+ //
1172
+ // Parameters:
1173
+ // ppEnvironmentBlock:
1174
+ // address of environment block buffer or NULL, receives reallocated buffer if necessary.
1175
+ //
1176
+ // pdwBlockLength:
1177
+ // address of current block length or zero, receives updated block length.
1178
+ //
1179
+ // dwBlockOffset:
1180
+ // current block offset.
1181
+ //
1182
+ // dwNeededLength:
1183
+ // needed allocation length not including nul terminator(s)
1184
+ static void win32_grow_environment_block(LPWSTR* ppEnvironmentBlock, DWORD* pdwBlockLength, DWORD dwBlockOffset, DWORD dwNeededLength)
1185
+ {
1186
+ DWORD dwOldLength = *pdwBlockLength;
1187
+ DWORD dwTerminatedLength = dwBlockOffset + dwNeededLength + 2; // need two nuls after last string
1188
+
1189
+ if (dwOldLength < dwTerminatedLength)
1190
+ {
1191
+ // generally double length to degrade grow frequency.
1192
+ DWORD dwNewLength = max(dwOldLength * 2, dwTerminatedLength);
1193
+
1194
+ dwNewLength = max(dwNewLength, 512);
1195
+
1196
+ // reallocate.
1197
+ {
1198
+ WCHAR* pOldBlock = *ppEnvironmentBlock;
1199
+ WCHAR* pNewBlock = (WCHAR*)malloc(dwNewLength * sizeof(WCHAR));
1200
+
1201
+ if (NULL != pOldBlock)
1202
+ {
1203
+ memcpy(pNewBlock, pOldBlock, dwOldLength * sizeof(WCHAR));
1204
+ }
1205
+ ZeroMemory(pNewBlock + dwOldLength, (dwNewLength - dwOldLength) * sizeof(WCHAR));
1206
+ if (NULL != pOldBlock)
1207
+ {
1208
+ free(pOldBlock);
1209
+ pOldBlock = NULL;
1210
+ }
1211
+ *ppEnvironmentBlock = pNewBlock;
1212
+ *pdwBlockLength = dwNewLength;
1213
+ }
1214
+ }
1215
+ }
1216
+
1217
+ // Summary:
1218
+ // reallocates the buffer needed to contain the given name/value pair and
1219
+ // copies the name/value pair in expected format to the end of the
1220
+ // environment block.
1221
+ //
1222
+ // Parameters:
1223
+ // pValueName:
1224
+ // nul-terminated value name
1225
+ //
1226
+ // dwValueNameLength:
1227
+ // length of value name not including nul terminator
1228
+ //
1229
+ // pValueData:
1230
+ // nul-terminated string or expand-string style value data
1231
+ //
1232
+ // dwValueDataLength:
1233
+ // length of value data not including nul terminator
1234
+ //
1235
+ // ppEnvironmentBlock:
1236
+ // result buffer to receive all name/value pairs or NULL to measure
1237
+ //
1238
+ // pdwBlockLength:
1239
+ // address of current buffer length or zero, receives updated length
1240
+ //
1241
+ // pdwBlockOffset:
1242
+ // address of current buffer offset or zero, receives updated offset
1243
+ static void win32_append_to_environment_block(LPCWSTR pValueName,
1244
+ DWORD dwValueNameLength,
1245
+ LPCWSTR pValueData,
1246
+ DWORD dwValueDataLength,
1247
+ LPWSTR* ppEnvironmentBlock,
1248
+ DWORD* pdwBlockLength,
1249
+ DWORD* pdwBlockOffset)
1250
+ {
1251
+ // grow, if necessary.
1252
+ DWORD dwNeededLength = dwValueNameLength + 1 + dwValueDataLength;
1253
+
1254
+ win32_grow_environment_block(ppEnvironmentBlock, pdwBlockLength, *pdwBlockOffset, dwNeededLength);
1255
+
1256
+ // copy name/value pair using "<value name>=<value data>\0" format.
1257
+ {
1258
+ DWORD dwBlockOffset = *pdwBlockOffset;
1259
+ LPWSTR pszBuffer = *ppEnvironmentBlock + dwBlockOffset;
1260
+
1261
+ memcpy(pszBuffer, pValueName, dwValueNameLength * sizeof(WCHAR));
1262
+ pszBuffer += dwValueNameLength;
1263
+ *pszBuffer++ = '=';
1264
+ memcpy(pszBuffer, pValueData, dwValueDataLength * sizeof(WCHAR));
1265
+ pszBuffer += dwValueDataLength;
1266
+ *pszBuffer = 0;
1267
+ }
1268
+
1269
+ // update offset.
1270
+ *pdwBlockOffset += dwNeededLength + 1;
1271
+ }
1272
+
1273
+ // Summary:
1274
+ // gets the environment strings from the registry for the machine.
1275
+ //
1276
+ // Returns:
1277
+ // nul-terminated block of nul-terminated environment strings as a Ruby string value.
1278
+ static VALUE right_popen_get_machine_environment(VALUE vSelf)
1279
+ {
1280
+ // open key.
1281
+ HKEY hKey = NULL;
1282
+ LPWSTR pEnvironmentBlock = NULL;
1283
+ DWORD dwValueCount = 0;
1284
+ DWORD dwMaxValueNameLength = 0;
1285
+ DWORD dwMaxValueDataSizeBytes = 0;
1286
+ DWORD dwResult = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
1287
+ L"SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Environment",
1288
+ 0,
1289
+ KEY_READ,
1290
+ &hKey);
1291
+ if (ERROR_SUCCESS != dwResult)
1292
+ {
1293
+ rb_raise(rb_eRuntimeError, "RegOpenKeyExW() failed: %s", win32_error_description(dwResult));
1294
+ }
1295
+
1296
+ // query key info.
1297
+ dwResult = RegQueryInfoKeyW(hKey, // key handle
1298
+ NULL, // buffer for class name
1299
+ NULL, // size of class string
1300
+ NULL, // reserved
1301
+ NULL, // number of subkeys
1302
+ NULL, // longest subkey size
1303
+ NULL, // longest class string
1304
+ &dwValueCount, // number of values for this key
1305
+ &dwMaxValueNameLength, // longest value name
1306
+ &dwMaxValueDataSizeBytes, // longest value data
1307
+ NULL, // security descriptor
1308
+ NULL); // last write time
1309
+ if (ERROR_SUCCESS != dwResult)
1310
+ {
1311
+ RegCloseKey(hKey);
1312
+ rb_raise(rb_eRuntimeError, "RegQueryInfoKeyW() failed: %s", win32_error_description(dwResult));
1313
+ }
1314
+
1315
+ // enumerate values and create result block.
1316
+ {
1317
+ LPWSTR pszValueName = (WCHAR*)malloc((dwMaxValueNameLength + 1) * sizeof(WCHAR));
1318
+ BYTE* pValueData = (BYTE*)malloc(dwMaxValueDataSizeBytes);
1319
+
1320
+ ZeroMemory(pszValueName, (dwMaxValueNameLength + 1) * sizeof(WCHAR));
1321
+ ZeroMemory(pValueData, dwMaxValueDataSizeBytes);
1322
+ {
1323
+ // enumerate values.
1324
+ //
1325
+ // note that there is nothing to prevent the data changing while
1326
+ // the key is open for reading; we need to be cautious and not
1327
+ // overrun the queried data buffer size in the rare case that the
1328
+ // max data increases in size.
1329
+ DWORD dwBlockLength = 0;
1330
+ DWORD dwBlockOffset = 0;
1331
+ DWORD dwValueIndex = 0;
1332
+
1333
+ for (; dwValueIndex < dwValueCount; ++dwValueIndex)
1334
+ {
1335
+ DWORD dwValueNameLength = dwMaxValueNameLength + 1;
1336
+ DWORD dwValueDataSizeBytes = dwMaxValueDataSizeBytes;
1337
+ DWORD dwValueType = REG_NONE;
1338
+
1339
+ dwResult = RegEnumValueW(hKey,
1340
+ dwValueIndex,
1341
+ pszValueName,
1342
+ &dwValueNameLength,
1343
+ NULL,
1344
+ &dwValueType,
1345
+ pValueData,
1346
+ &dwValueDataSizeBytes);
1347
+
1348
+ // ignore any failures but continue on to next value.
1349
+ if (ERROR_SUCCESS == dwResult)
1350
+ {
1351
+ // only expecting string and expand string values; ignore anything else.
1352
+ switch (dwValueType)
1353
+ {
1354
+ case REG_EXPAND_SZ:
1355
+ case REG_SZ:
1356
+ {
1357
+ // byte size of Unicode string value must be even and include nul terminator.
1358
+ if (0 == (dwValueDataSizeBytes % sizeof(WCHAR)) && dwValueDataSizeBytes >= sizeof(WCHAR))
1359
+ {
1360
+ LPWSTR pszValueData = (LPWSTR)pValueData;
1361
+ DWORD dwValueDataLength = (dwValueDataSizeBytes / sizeof(WCHAR)) - 1;
1362
+
1363
+ if (0 == pszValueData[dwValueDataLength])
1364
+ {
1365
+ // need to expand (pseudo) environment variables for expand string values.
1366
+ if (REG_EXPAND_SZ == dwValueType)
1367
+ {
1368
+ DWORD dwExpandedDataLength = ExpandEnvironmentStringsW(pszValueData, NULL, 0);
1369
+ LPWSTR pszExpandedData = (WCHAR*)malloc(dwExpandedDataLength * sizeof(WCHAR));
1370
+
1371
+ ZeroMemory(pszExpandedData, dwExpandedDataLength * sizeof(WCHAR));
1372
+ if (dwExpandedDataLength == ExpandEnvironmentStringsW(pszValueData, pszExpandedData, dwExpandedDataLength))
1373
+ {
1374
+ win32_append_to_environment_block(pszValueName,
1375
+ dwValueNameLength,
1376
+ pszExpandedData,
1377
+ dwExpandedDataLength - 1,
1378
+ &pEnvironmentBlock,
1379
+ &dwBlockLength,
1380
+ &dwBlockOffset);
1381
+ }
1382
+ free(pszExpandedData);
1383
+ pszExpandedData = NULL;
1384
+ }
1385
+ else
1386
+ {
1387
+ win32_append_to_environment_block(pszValueName,
1388
+ dwValueNameLength,
1389
+ pszValueData,
1390
+ dwValueDataLength,
1391
+ &pEnvironmentBlock,
1392
+ &dwBlockLength,
1393
+ &dwBlockOffset);
1394
+ }
1395
+ }
1396
+ }
1397
+ }
1398
+ }
1399
+ }
1400
+ }
1401
+
1402
+ // handle corner case of no (valid) machine environment values.
1403
+ if (NULL == pEnvironmentBlock)
1404
+ {
1405
+ win32_grow_environment_block(&pEnvironmentBlock, &dwBlockLength, dwBlockOffset, 0);
1406
+ }
1407
+ }
1408
+
1409
+ // free temporary buffers.
1410
+ free(pszValueName);
1411
+ pszValueName = NULL;
1412
+ free(pValueData);
1413
+ pValueData = NULL;
1414
+ }
1415
+
1416
+ // close.
1417
+ RegCloseKey(hKey);
1418
+ hKey = NULL;
1419
+
1420
+ // convert environment block to a Ruby string.
1421
+ {
1422
+ VALUE value = win32_unicode_environment_block_to_ruby(pEnvironmentBlock);
1423
+
1424
+ free(pEnvironmentBlock);
1425
+ pEnvironmentBlock = NULL;
1426
+
1427
+ return value;
1428
+ }
1429
+ }
1430
+
1169
1431
  // Summary:
1170
1432
  // gets the environment strings for the current process.
1171
1433
  //
@@ -1200,5 +1462,6 @@ void Init_right_popen()
1200
1462
  rb_define_module_function(vModule, "popen4", (VALUE(*)(ANYARGS))right_popen_popen4, -1);
1201
1463
  rb_define_module_function(vModule, "async_read", (VALUE(*)(ANYARGS))right_popen_async_read, 1);
1202
1464
  rb_define_module_function(vModule, "get_current_user_environment", (VALUE(*)(ANYARGS))right_popen_get_current_user_environment, 0);
1465
+ rb_define_module_function(vModule, "get_machine_environment", (VALUE(*)(ANYARGS))right_popen_get_machine_environment, 0);
1203
1466
  rb_define_module_function(vModule, "get_process_environment", (VALUE(*)(ANYARGS))right_popen_get_process_environment, 0);
1204
1467
  }
@@ -265,9 +265,13 @@ module RightScale
265
265
  # merged string block
266
266
  def self.merge_environment(environment_hash)
267
267
  current_user_environment_hash = get_current_user_environment
268
+ machine_environment_hash = get_machine_environment
268
269
  result_environment_hash = get_process_environment
269
270
 
270
- # user environment from registry supercedes process.
271
+ # machine from registry supercedes process.
272
+ merge_environment2(machine_environment_hash, result_environment_hash)
273
+
274
+ # user environment from registry supercedes machine and process.
271
275
  merge_environment2(current_user_environment_hash, result_environment_hash)
272
276
 
273
277
  # caller's environment supercedes all.
@@ -347,10 +351,9 @@ module RightScale
347
351
  end
348
352
 
349
353
  # Queries the environment strings from the current thread/process user's
350
- # environment (which is stored in the registry on Windows as a combination of
351
- # system and user-specific environment variables). The resulting hash
352
- # represents any variables set for the persisted user context but any set
353
- # dynamically in the current process context.
354
+ # environment. The resulting hash represents any variables set for the
355
+ # persisted user context but any set dynamically in the current process
356
+ # context.
354
357
  #
355
358
  # === Returns
356
359
  # environment_hash(Hash):: hash of environment key (String) to value (String).
@@ -360,6 +363,16 @@ module RightScale
360
363
  return string_block_to_environment_hash(environment_strings)
361
364
  end
362
365
 
366
+ # Queries the environment strings from the machine's environment.
367
+ #
368
+ # === Returns
369
+ # environment_hash(Hash):: hash of environment key (String) to value (String).
370
+ def self.get_machine_environment
371
+ environment_strings = RightPopen.get_machine_environment
372
+
373
+ return string_block_to_environment_hash(environment_strings)
374
+ end
375
+
363
376
  # Queries the environment strings from the process environment (which is kept
364
377
  # in memory for each process and generally begins life as a copy of the
365
378
  # process user's environment context plus any changes made by ancestral
Binary file
data/right_popen.gemspec CHANGED
@@ -6,7 +6,7 @@ end
6
6
 
7
7
  spec = Gem::Specification.new do |spec|
8
8
  spec.name = 'right_popen'
9
- spec.version = '1.0.5'
9
+ spec.version = '1.0.6'
10
10
  spec.authors = ['Scott Messier', 'Raphael Simon']
11
11
  spec.email = 'scott@rightscale.com'
12
12
  spec.homepage = 'https://github.com/rightscale/right_popen'
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: right_popen
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.5
4
+ version: 1.0.6
5
5
  platform: x86-mswin32-60
6
6
  authors:
7
7
  - Scott Messier
@@ -10,7 +10,7 @@ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
12
 
13
- date: 2010-02-23 00:00:00 -08:00
13
+ date: 2010-03-16 00:00:00 -07:00
14
14
  default_executable:
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency