📄 nonport.cpp
字号:
if (isDirectory) { len++; // also consider final '\0' (strchr returns ptr to it) } // start at 1 (and not 0) because if the path starts with a slash, // then starting at 0 will cause us to try mkdir("") for (int i=1; i < len; i++) { if (strchr(DIRSLASHES, temp[i])) { // wherever there is a slash (or '\0'), truncate and test temp[i] = '\0'; if (!fileOrDirectoryExists(temp)) { // make directory if necessary; automatically limits file access if (!createDirectory(temp)) { delete[] temp; return false; } } temp[i] = DIRSLASH; // may kill final '\0', doesn't matter } } // was leaking this.. found the leak with the feudal-C instrumentor! delete[] temp; return true;}#ifdef USE_DEV_SRANDOM #define DEV_RANDOM "/dev/srandom" // for OpenBSD#else #define DEV_RANDOM "/dev/random" // linux, etc.#endif// underlying testbool hsrcHelper(){ // I don't use FreeBSD's /dev/random because: // - there are comments in the source for /dev/random (at least // in some 5.x versions) suggest it isn't cryptographically // secure; if so, I don't think /dev/random should appear in // the filesystem by default // - it doesn't block when the entropy pool is empty, and I don't // want to busy-wait for more entropy to arrive // - the default configuration won't yield any data at all, because // no IRQs are set up to gather entropy (see rndcontrol(8)) #if defined(__UNIX__) && !defined(__FREEBSD__) // if this takes more than three seconds, something is wrong; // after 3 seconds we'll get a SIGALRM which will kill the process alarm(3); // see if /dev/random exists and is readable int fd = open(DEV_RANDOM, O_RDONLY); if (fd < 0) { return false; } // I considered trying to grab 32 bits of entropy to test it, // but since this is run on every process run, that might be // a bit wasteful of entropy // looks ok! if (close(fd) < 0) { perror("close"); return false; // seems unlikely, but.. } // ok, disable the alarm now alarm(0); return true; #else // windows return false; #endif}// thread safety: worst case is multiple calls to hsrcHelper, since// the boolean only changes monotonically, so it's safebool hasSystemCryptoRandom(){ #ifdef NO_DEV_RANDOM return false; #else static bool cached = false; static bool cachedAnswer; if (!cached) { cachedAnswer = hsrcHelper(); cached = true; } return cachedAnswer; #endif}// assume we are only called if the above fn returned true;// for this fn, any failure is considered fatal because we// don't have a way to communicate it, and the possibility of// returning nonrandom values is not tolerable (if something// I haven't thought of is causing failure, add it to the list// of things hasSystemCryptoRandom checks)unsigned getSystemCryptoRandom(){ #ifdef __UNIX__ // if this takes more than three seconds, something is wrong; // after 3 seconds we'll get a SIGALRM which will kill the process alarm(3); // open /dev/random int fd = open(DEV_RANDOM, O_RDONLY); if (!fd) { perror("open"); exit(2); } // grab 4 bytes union { unsigned ret; char c[4]; }; int got = 0; while (got < 4) { int ct = read(fd, c+got, 4-got); if (ct < 0) { perror("read"); exit(2); } if (ct == 0) { // this actually happens under FreeBSD, and is part of // why I don't use FreeBSD's /dev/random fprintf(stderr, "got 0 bytes from %s.. it's supposed to block!!\n", DEV_RANDOM); exit(2); } got += ct; } if (close(fd) < 0) { perror("close"); exit(2); } // ok, disable the alarm now alarm(0); return ret; #else // windows fprintf(stderr, "no system crypto random function available!\n"); exit(2); return 0; // silence warning #endif}int getProcessId(){ #ifdef __UNIX__ return getpid(); #else // windows return GetCurrentProcessId(); #endif}#ifdef WIN32static class _critsec_class { private: CRITICAL_SECTION critsec; // these are _not_ necessary (CRITICAL_SECTION gives us everything we need) // but they're useful for preventing bad behavior which has undefined results // (e.g. calling leave() when you don't own the lock, which WIN32 API says causes undefined behavior ) DWORD currentOwner; bool noOwner; DWORD lockCount; void init() { static bool initcomplete = false; if (initcomplete) return; InitializeCriticalSection(&critsec); currentOwner = 0; noOwner = true; lockCount = 0; initcomplete = true; } public: _critsec_class() { // gets called automatically at program startup by startup thread init(); } ~_critsec_class() { // DeleteCriticalSection(&critsec); // we just leak this critical section, because otherwise there's no way to handle locks called // from static destructors } void enter() { init(); // necessary to enforce initialization when called from another static initializer // (note in this case there is always exactly one thread in the process, i.e. the startup thread) EnterCriticalSection(&critsec); // block until available // do some checking to ensure sanity DWORD myid = GetCurrentThreadId(); assert((noOwner && lockCount == 0) || (currentOwner == myid && lockCount > 0)); currentOwner = myid; noOwner = false; lockCount++; } void leave() { // do some checking to ensure sanity DWORD myid = GetCurrentThreadId(); assert(currentOwner == myid && lockCount > 0); lockCount--; if (lockCount == 0) { currentOwner = 0; noOwner = true; } LeaveCriticalSection(&critsec); // leave the critical section }} myCritSec;#endif// enter a critical section - blocks until section is free// used for synchronizing across threads in a single process// note there is only one critical section object here // a single thread may call this multiple times without being blocked// but must call portableUnlock() the same number of timesvoid portableLock() { #ifdef _MT // defined automatically on MSVC for multi-threaded code #ifdef WIN32 myCritSec.enter(); #else abort(); // make sure we never claim to provide mutual exclusion if we really don't #endif #endif }// leave a critical section // this thread must have previously successfully executed a portableLock() callvoid portableUnlock() { #ifdef _MT // defined automatically on MSVC for multi-threaded code #ifdef WIN32 myCritSec.leave(); #else abort(); // make sure we never claim to provide mutual exclusion if we really don't #endif #endif }// ----------------- test code --------------------#ifdef TEST_NONPORT#include <stdio.h> // printf// helper for testing applyToCwdFilesbool printFirst10(char const *name, void *extra){ int &count = *((int*)extra); count++; if (count <= 10) { printf(" %s\n", name); return true; // continue } else { return false; // stop }}bool printIt(char const *name, void*){ printf("%s\n", name); return true; // continue}void testingFail(char const *call, char const *ctx){ printf("FAIL: call=%s, ctx=%s, errno=%d\n", call, (ctx? ctx : "(null)"), errno);}int main(int argc, char **argv){ nonportFail = testingFail; if (argc > 1) { // -ls: list directory if (0==strcmp(argv[1], "-ls")) { applyToCwdContents(printIt); return 0; } // -hasRandom: test whether /dev/random exists and is usable if (0==strcmp(argv[1], "-hasRandom")) { if (hasSystemCryptoRandom()) { getSystemCryptoRandom(); getSystemCryptoRandom(); return 0; // yes } else { return 2; // no } } printf("unknown argument: %s\n", argv[1]); return 2; } // trying to figure out why backspace sometimes gives ^? crap // (turns out Konsole sometimes sends ^? in response to BS, // even when the option looks unchecked) //char buf[80]; //printf("type stuff and try backspace: "); //gets(buf); //printf("%s (%d chars)\n", buf, strlen(buf)); //return 0; #if 0 // annoying during 'make check' long startTime = getMilliseconds(); printf("Type some characters; you should see each\n" "character echoed once as you type it (q to stop):\n"); setRawMode(true); char ch; do { ch = getConsoleChar(); printf("%c", ch); } while (ch != 'q'); setRawMode(false); printf("\n\nYou typed for %ld milliseconds\n", getMilliseconds() - startTime); #endif // 0 limitFileAccess("chmod.test"); printf("if the current dir contains a file called " "chmod.test, I just attempted to limit\n" "its access to just the owner\n"); createDirectory("test.dir"); // test chdir, which also implicitly tests mkdir bool didFirst=false; if (!changeDirectory("test.dir") || (didFirst=true, false) || !changeDirectory("..")) { printf("failed while trying to chdir to %s\n", (didFirst? ".." : "test.dir")); } // more straightforward if (!fileOrDirectoryExists("test.dir")) { printf("test.dir didn't get created?\n"); } printf("what's more, I just tried to mkdir & chdir test.dir\n"); // test ensurePath if (!ensurePath("test.dir/a/b/c/d", false /*isDirectory*/)) { printf("ensurePath test.dir/a/b/c/d failed\n"); } // try to list partial directory contents printf("listing of first 10 files in this directory:\n"); { int count = 0; applyToCwdContents(printFirst10, &count); } // test date function { int m, d, y; getCurrentDate(m, d, y); printf("I think the date is (m/d/yyyy): %d/%d/%d\n", m, d, y); } // and time { int h, m, s; getCurrentTime(h, m, s); printf("and the time is (hh:mm:ss): %02d:%02d:%02d\n", h, m, s); } // test sleep (mostly just to make sure it doesn't segfault) printf("sleeping for 1 second...\n"); portableSleep(1); // test user name char buf[80]; getCurrentUsername(buf, 80); printf("current user name is: %s\n", buf); #if 0 // annoying during 'make check' // test nonecho reading printf("Type something and press Enter; it won't be echoed (yet):\n"); readNonechoString(buf, 80, " > "); printf("You typed: %s\n", buf); #endif // 0 // test random stuff printf("Testing %s; if this dies with an \"Alarm clock\"\n" "message, then something is wrong with %s.\n", DEV_RANDOM, DEV_RANDOM); printf("hasSystemCryptoRandom: "); if (!hasSystemCryptoRandom()) { printf("no\n"); } else { printf("yes\n"); printf("three random numbers: %u %u %u\n", getSystemCryptoRandom(), getSystemCryptoRandom(), getSystemCryptoRandom()); } // and process id printf("my process id is %d\n", getProcessId()); return 0;}#endif // TEST_NONPORT// -------------- trash ----------------#if 0void limitFileAccess(char const *fname){ // we'll decide whether this is possible by whether // or not the necessary macros are defined#ifndef S_IRGRP // assume rest are if this is // probably can't do anything return;#else // modify file permissions (to simplify things, // we'll just set permissions, rather than // read-modify-write); don't bother testing for // error condition since there isn't much we // can do about it anyway chmod(fname, S_IRUSR | S_IWUSR);# endif}# ifdef __WIN32__ // findfirst, findnext# ifdef __BORLANDC__ struct ffblk fb; int done = findfirst("*", &fb, 0); while (!done) { if (!func(fb.ff_name, extra)) { break; } done = findnext(&fb); }# else // DOB: VC has a totally diff interface for this struct _finddata_t fb; long handle = _findfirst("*", &fb); int done = (handle == -1); while (!done) { if (!func(fb.name, extra)) { break; } done = _findnext(handle, &fb); } if (handle != -1) _findclose(handle);# endif# else // unix // {open,read,close}dir, stat# endif#endif // 0 (trash)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -