#include "fat.h" #include int passed = 0, failed = 0; #define CHECK(x, what) \ do { \ std::cout << what << "...";; \ if (x) { \ std::cout << "passed.\n"; \ ++passed; \ } else { \ std::cout << "failed.\n"; \ ++failed; \ } \ } while (0) #define CONGRATS_TEXT \ "Congratulations, you have gotten something working!\n"\ "\n"\ "Now that you can wade through the FAT with the greatest of ease, you can\n"\ "undercut all of those $30 shareware \"Undelete\" applications that market\n"\ "to people with digital camera and USB drive dysfunctions. Go forth and\n"\ "take advantage of other people's misfortunes!\n"\ "\n"\ "Only $19.99!!!!\n"\ "\n"\ "-Duane\n"\ "\n" #define THE_GAME_TEXT \ "Subject: for your amusement\n" \ "To: csfaculty@uvacs.cs.virginia.edu\n" \ "Date: Thu, 23 Mar 1995 10:49:33 -0500 (EST)\n" \ "Content-Type: text/plain; charset=US-ASCII\n" \ "Content-Transfer-Encoding: 7bit\n" \ "Status: RO\n" \ "Content-Length: 4226\n" \ "\n" \ "> Software - How Software Companies Die\n" \ "> By: Orson Scott Card\n" \ "> \n" \ "> The environment that nutures creative programmers kills management\n" \ "> and marketing types - and vice versa. Programming is the Great Game.\n" \ "> It consumes you, body and soul. When you're caught up in it, nothing\n" \ "> else matters. When you emerge into daylight, you might well discover\n" \ "> that you're a hundred pounds overweight, your underwear is older than\n" \ "> the average first grader, and judging from the number of pizza boxes\n" \ "> lying around, it must be spring already. But you don't care, because\n" \ "> your program runs, and the code is fast and clever and tight. You won.\n" \ "> You're aware that some people think you're a nerd. So what? They're\n" \ "> not players. They've never jousted with Windows or gone hand to hand\n" \ "> with DOS. To them C++ is a decent grade, almost a B - not a language.\n" \ "> They barely exist. Like soldiers or artists, you don't care about the\n" \ "> opinions of civilians. You're building something intricate and fine.\n" \ "> They'll never understand it.\n" \ "> \n" \ "> BEEKEEPING\n" \ "> \n" \ "> Here's the secret that every successful software company is based on:\n" \ "> You can domesticate programmers the way beekeepers tame bees. You\n" \ "> can't exactly communicate with them, but you can get them to swarm in\n" \ "> one place and when they're not looking, you can carry off the honey.\n" \ "> You keep these bees from stinging by paying them money. More money\n" \ "> than they know what to do with. But that's less than you might think.\n" \ "> You see, all these programmers keep hearing their parents' voices in\n" \ "> their heads saying \"When are you going to join the real world?\" All\n" \ "> you have to pay them is enough money that they can answer (also in\n" \ "> their heads) \"Geez, Dad, I'm making more than you.\" On average, this\n" \ "> is cheap. And you get them to stay in the hive by giving them other\n" \ "> coders to swarm with. The only person whose praise matters is another\n" \ "> programmer. Less-talented programmers will idolize them; evenly\n" \ "> matched ones will challenge and goad one another; and if you want to\n" \ "> get a good swarm, you make sure that you have at least one certified\n" \ "> genius coder that they can all look up to, even if he glances at other\n" \ "> people's code only long enough to sneer at it. He's a Player, thinks\n" \ "> the junior programmer. He looked at my code. That is enough. If a\n" \ "> software company provides such a hive, the coders will give up sleep,\n" \ "> love, health, and clean laundry, while the company keeps the bulk of\n" \ "> the money.\n" \ "> \n" \ "> OUT OF CONTROL\n" \ "> \n" \ "> Here's the problem that ends up killing company after company. All\n" \ "> successful software companies had, as their dominant personality, a\n" \ "> leader who nurtured programmers. But no company can keep such a leader\n" \ "> forever. Either he cashes out, or he brings in management types who end\n" \ "> up driving him out, or he changes and becomes a management type himself.\n" \ "> One way or another, marketers get control. But...control of what?\n" \ "> Instead of finding assembly lines of productive workers, they quickly\n" \ "> discover that their product is produced by utterly unpredictable,\n" \ "> uncooperative, disobedient, and worst of all, unattractive people who\n" \ "> resist all attempts at management. Put them on a time clock, dress\n" \ "> them in suits, and they become sullen and start sabotaging the product.\n" \ "> Worst of all, you can sense that they are making fun of you with every\n" \ "> word they say.\n" \ "> \n" \ "> SMOKED OUT\n" \ "> \n" \ "> The shock is greater for the coder, though. He suddenly finds that\n" \ "> alien creatures control his life. Meetings, Schedules, Reports. And\n" \ "> now someone demands that he PLAN all his programming and then stick to\n" \ "> the plan, never improving, never tweaking, and never, never touching\n" \ "> some other team's code. The lousy young programmer who once worshiped\n" \ "> him is now his tyrannical boss, a position he got because he played\n" \ "> golf with some sphincter in a suit. The hive has been ruined. The best\n" \ "> coders leave. And the marketers, comfortable now because they're\n" \ "> surrounded by power neckties and they have things under control, are\n" \ "> baffled that each new iteration of their software loses market share\n" \ "> as the code bloats and the bugs proliferate. Got to get some better\n" \ "> packaging. Yeah, that's it.\n" \ "\n" void check_root_dir(const std::string &path) { bool saw_people = false; bool saw_congrats = false; for (AnyDirEntry entry : FAT_readdir(path)) { if (entry.dir.DIR_Attr != DirEntryAttributes::LONG_NAME) { std::string name((char*) entry.dir.DIR_Name, (char*) entry.dir.DIR_Name + 11); if (name == "PEOPLE ") { saw_people = true; CHECK(entry.dir.DIR_Attr & DirEntryAttributes::DIRECTORY, "people is a directory"); } else if (name == "CONGRATSTXT") { saw_congrats = true; } } } CHECK(saw_people, "people directory was found in " << path); CHECK(saw_congrats, "congrats.txt was found in " << path); } void check_is_congrats(const std::string &path) { int fd = FAT_open(path); CHECK(fd >= 0, "opening congrats.txt via " << path << " returned >= 0 fd"); if (fd >= 0) { char buffer[4096]; int count = FAT_pread(fd, (void*) buffer, sizeof buffer, 0); CHECK(count == 342, "pread from congrats.txt at offset 0 read 342 bytes"); CHECK(std::string(buffer, buffer + count) == CONGRATS_TEXT, "contents of congrats.txt"); for (int i = 0; i < 340; i += 20) { count = FAT_pread(fd, (void*) buffer, sizeof buffer, i); CHECK(count == 342 - i, "pread from congrats.txt at offset " << i << " returned correct # of bytes"); CHECK(std::string(buffer, buffer + count) == std::string(CONGRATS_TEXT + i), "contents of congrats.txt subset"); } count = FAT_pread(fd, (void*) buffer, 300, 0); CHECK(count == 300, "pread at offset 0 from congrats.txt with count of 300 reads 300"); CHECK(std::string(buffer, buffer + count) == std::string(CONGRATS_TEXT, CONGRATS_TEXT + 300), "contents of congrats.txt subset"); count = FAT_pread(fd, (void*) buffer, sizeof buffer, 1000); CHECK(count == 0, "pread at offset 1000 from congrats.txt reads 0"); FAT_close(fd); } } void check_is_the_game(const std::string &path) { int fd = FAT_open(path); CHECK(fd >= 0, "opening the-game.txt via " << path << " returned >= 0 fd"); if (fd >= 0) { char buffer[8192]; int count = FAT_pread(fd, (void*) buffer, sizeof buffer, 0); CHECK(count == 4443, "pread from the-game.txt at offset 0 read 4443 bytes"); CHECK(std::string(buffer, buffer + count) == THE_GAME_TEXT, "contents of the-game.txt"); count = FAT_pread(fd, (void*) buffer, sizeof buffer, 1000); CHECK(count == 3443, "pread from the-game.txt at offset 1000 read 3443 bytes"); CHECK(std::string(buffer, buffer + count) == THE_GAME_TEXT + 1000, "contents of the-game.txt subset"); count = FAT_pread(fd, (void*) buffer, 500, 600); CHECK(count == 500, "pread from the-game.txt at offset 600 with count 500 read 500 bytes"); CHECK(std::string(buffer, buffer + count) == std::string(THE_GAME_TEXT + 600, THE_GAME_TEXT + 600 + count), "contents of the-game.txt subset"); count = FAT_pread(fd, (void*) buffer, sizeof buffer, 5000); CHECK(count == 0, "pread from the-game.txt at offset 5000 read 0 bytes"); FAT_close(fd); } } void check_not_openable(const std::string &path) { int fd = FAT_open(path); CHECK(fd == -1, "opening " << path << " fails"); if (fd >= 0) { FAT_close(fd); } } int main(int argc, char **argv) { check_not_openable("/congrats.txt"); CHECK(FAT_readdir("/").size() == 0, "cannot read / before mounting"); CHECK(!FAT_cd("people"), "cannot cd before mounting"); bool mounted = FAT_mount("sampledisk32.raw"); CHECK(mounted, "mounting sampledisk32.raw successful"); if (!mounted) { std::cerr << "could not mount sampledisk32.raw, skipping rest of tests\n"; std::cerr << "(is that file in this directory?)\n"; return 1; } check_root_dir("/"); check_root_dir("/people/.."); check_root_dir("/PEoPLE/.."); check_root_dir("/Media/.."); check_not_openable("/people"); check_is_congrats("/congrats.txt"); check_is_congrats("/congrAts.tXt"); check_is_congrats("congrats.txt"); check_is_congrats("people/../congrats.txt"); check_is_congrats("people/../people/../people/../people/../congrats.txt"); check_is_the_game("/people/yyz5w/the-game.txt"); check_is_the_game("people/yyz5w/the-game.txt"); CHECK(!FAT_cd("yyz5w"), "cannot cd to yyz5w from root directory"); CHECK(FAT_cd("people"), "successfully cd'd to people directory"); check_not_openable("congrats.txt"); check_not_openable("the-game.txt"); check_is_the_game("yyz5w/the-game.txt"); check_is_the_game("./yyz5w/the-game.txt"); check_is_the_game("/people/yyz5w/the-game.txt"); CHECK(!FAT_cd("people"), "cannot cd to people from people directory"); CHECK(FAT_cd(".."), "successfully cd'd from people to parent directory"); check_is_the_game("people/yyz5w/the-game.txt"); CHECK(FAT_cd("people"), "successfullly cd'd to people directory (second time)"); CHECK(FAT_cd("yyz5w"), "successfully cd'd to people directory"); CHECK(!FAT_cd("the-game.txt"), "cannot cd to non-directory the-game.txt"); CHECK(!FAT_cd("/people/yyz5w/the-game.txt"), "cannot cd to non-directory the-game.txt"); CHECK(!FAT_cd("/congrats.txt"), "cannot cd to non-directory congrats.txt"); check_is_the_game("the-game.txt"); check_is_the_game("../YYZ5W/the-game.txt"); check_is_congrats("../../congrats.txt"); check_root_dir("../.."); CHECK(FAT_cd(".."), "cd to people from /people/yyz5w using .."); check_is_congrats("../congrats.txt"); check_is_congrats("/congrats.txt"); CHECK(FAT_cd("../media"), "successfully cd'd to ../media directory from people directory"); check_is_congrats("../congrats.txt"); check_is_congrats("/congrats.txt"); std::cout << "passed " << passed << " and failed " << failed << std::endl; }