00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #ifndef WIN32
00027 #include "Aria.h"
00028 #include "ArExport.h"
00029 #include "ArServerFileUtils.h"
00030
00031 #include <sys/types.h>
00032 #include <dirent.h>
00033 #include <ctype.h>
00034
00045 AREXPORT bool ArServerFileUtil::squashCase(const char *baseDir,
00046 const char *fileName,
00047 char *result,
00048 size_t resultLen)
00049 {
00050 DIR *dir;
00051 struct dirent *ent;
00052
00053 char separator;
00054 #ifndef WIN32
00055 separator = '/';
00056 #else
00057 separator = '\\';
00058 #endif
00059
00060 result[0] = '\0';
00061 std::list<std::string> split;
00062 split = splitFileName(fileName);
00063 std::list<std::string>::iterator it;
00064 std::string finding;
00065
00066
00067
00068
00069
00070
00071
00072 it = split.begin();
00073 finding = (*it);
00074
00075
00076
00077
00078
00079
00080
00081 if ((dir = opendir(baseDir)) == NULL)
00082 {
00083 ArLog::log(ArLog::Normal,
00084 "ArServerFileUtil: No such directory '%s' for base",
00085 baseDir);
00086 return false;
00087 }
00088
00089 while ((ent = readdir(dir)) != NULL)
00090 {
00091
00092 if (ent->d_name[0] == '.')
00093 {
00094
00095 continue;
00096 }
00097
00098
00099
00100 if (ArUtil::strcasecmp(ent->d_name, finding) == 0)
00101 {
00102 size_t lenOfResult;
00103 lenOfResult = strlen(result);
00104
00105
00106 if (strlen(ent->d_name) > resultLen - lenOfResult - 2)
00107 {
00108 ArLog::log(ArLog::Normal,
00109 "ArServerFileUtil::squashCase: result not long enough");
00110 return false;
00111 }
00112
00113 if (lenOfResult != 0)
00114 {
00115 result[lenOfResult] = separator;
00116 result[lenOfResult+1] = '\0';
00117 }
00118
00119 strcpy(&result[strlen(result)], ent->d_name);
00120
00121
00122 it++;
00123 if (it != split.end())
00124 {
00125
00126 finding = (*it);
00127 std::string wholeDir;
00128 wholeDir = baseDir;
00129 wholeDir += result;
00130
00131 if ((dir = opendir(wholeDir.c_str())) == NULL)
00132 {
00133 ArLog::log(ArLog::Normal,
00134 "ArServerFileUtil::squashCase: Error going into %s",
00135 result);
00136 return false;
00137 }
00138 }
00139 else
00140 {
00141
00142 return true;
00143 }
00144 }
00145 }
00146 ArLog::log(ArLog::Verbose,
00147 "ArServerFileUtil::squashCase: %s doesn't exist in %s", fileName,
00148 baseDir);
00149 return false;
00150 }
00151
00152 AREXPORT bool ArServerFileUtil::getDirectory(const char *fileName,
00153 char *result, size_t resultLen)
00154 {
00155 char separator;
00156 #ifndef WIN32
00157 separator = '/';
00158 #else
00159 separator = '\\';
00160 #endif
00161
00162 if (fileName == NULL || fileName[0] == '\0' || resultLen == 0)
00163 {
00164 ArLog::log(ArLog::Normal, "ArServerFileUtil: getDirectory, bad setup");
00165 return false;
00166 }
00167
00168
00169 strncpy(result, fileName, resultLen - 1);
00170
00171 result[resultLen - 1] = '\0';
00172 char *toPos;
00173 ArUtil::fixSlashes(result, resultLen);
00174
00175 toPos = strrchr(result, separator);
00176
00177 if (toPos == NULL)
00178 {
00179 result[0] = '\0';
00180 return true;
00181 }
00182
00183 else
00184 {
00185 *toPos = '\0';
00186 return true;
00187 }
00188 }
00189
00190 AREXPORT bool ArServerFileUtil::getFileName(const char *fileName,
00191 char *result, size_t resultLen)
00192 {
00193 char separator;
00194 #ifndef WIN32
00195 separator = '/';
00196 #else
00197 separator = '\\';
00198 #endif
00199
00200 if (fileName == NULL || fileName[0] == '\0' || resultLen == 0)
00201 {
00202 ArLog::log(ArLog::Normal, "ArServerFileUtil: getFileName, bad setup");
00203 return false;
00204 }
00205
00206 char *str;
00207 size_t fileNameLen = strlen(fileName);
00208 str = new char[fileNameLen + 1];
00209
00210
00211 strncpy(str, fileName, fileNameLen);
00212
00213 str[fileNameLen] = '\0';
00214
00215
00216 char *toPos;
00217 ArUtil::fixSlashes(str, fileNameLen + 1);
00218
00219
00220 toPos = strrchr(str, separator);
00221
00222 if (toPos == NULL)
00223 {
00224
00225 strncpy(result, str, resultLen - 1);
00226 result[resultLen - 1] = '\0';
00227
00228 return true;
00229 }
00230
00231 else
00232 {
00233 strncpy(result, &str[toPos - str + 1], resultLen - 2);
00234 result[resultLen - 1] = '\0';
00235
00236
00237 return true;
00238 }
00239 }
00240
00244 std::list<std::string> ArServerFileUtil::splitFileName(
00245 const char *fileName)
00246 {
00247 std::list<std::string> split;
00248 if (fileName == NULL)
00249 return split;
00250
00251 char separator;
00252 #ifndef WIN32
00253 separator = '/';
00254 #else
00255 separator = '\\';
00256 #endif
00257
00258 size_t len;
00259 size_t i;
00260 size_t last;
00261 bool justSepped;
00262 char entry[2048];
00263 for (i = 0, justSepped = false, last = 0, len = strlen(fileName);
00264 ;
00265 i++)
00266 {
00267
00268 if ((fileName[i] == separator && !justSepped)
00269 || fileName[i] == '\0' || i >= len)
00270 {
00271 if (i - last > 2047)
00272 {
00273 ArLog::log(ArLog::Normal, "ArServerFileUtil::splitFileName: some directory or file too long");
00274 }
00275 if (!justSepped)
00276 {
00277 strncpy(entry, &fileName[last], i - last);
00278 entry[i-last] = '\0';
00279 split.push_back(entry);
00280 justSepped = true;
00281 }
00282 if (fileName[i] == '\0' || i >= len)
00283 return split;
00284 }
00285 else if (fileName[i] == separator && justSepped)
00286 {
00287 justSepped = true;
00288 last = i;
00289 }
00290 else if (fileName[i] != separator && justSepped)
00291 {
00292 justSepped = false;
00293 last = i;
00294 }
00295 }
00296 ArLog::log(ArLog::Normal, "ArServerFileUtil::splitFileName: file str ('%s') happened weird", fileName);
00297 return split;
00298 }
00299
00300 AREXPORT ArServerFileLister::ArServerFileLister(ArServerBase *server,
00301 const char *topDir) :
00302 myGetDirListingCB(this, &ArServerFileLister::getDirListing)
00303 {
00304 myServer = server;
00305 myServer->addData("getDirListing",
00306 "Gets the directory listing of a given directory (from the current working directory), you should probably use a class from ArClientFileUtils instead of calling this directly",
00307 &myGetDirListingCB, "string: directory to get listing of",
00308 "ubyte2: return code, 0 = good, 1 = tried to go outside allowed area, 2 = no such directory (or can't read); string: directoryListed; IF return was 0 then ubyte2: numDirectories; repeating numDirectories (string: name; ubyte4: access_time; ubyte4: modified_time); ubyte2: numFiles; repeating numFiles (string: name; ubyte4: access_time; ubyte4: modified_time);",
00309 "FileAccess", "RETURN_SINGLE");
00310
00311
00312 strncpy(myBaseDir, topDir, sizeof(myBaseDir) - 2);
00313 myBaseDir[sizeof(myBaseDir) - 2] = '\0';
00314
00315 ArUtil::appendSlash(myBaseDir, sizeof(myBaseDir));
00316
00317 ArUtil::fixSlashes(myBaseDir, sizeof(myBaseDir));
00318 }
00319
00320 AREXPORT ArServerFileLister::~ArServerFileLister()
00321 {
00322
00323 }
00324
00325 AREXPORT void ArServerFileLister::getDirListing(ArServerClient *client,
00326 ArNetPacket *packet)
00327 {
00328 ArNetPacket sendPacket;
00329 size_t ui;
00330 size_t len;
00331
00332 bool printing = false;
00333
00334 char directory[2048];
00335 packet->bufToStr(directory, sizeof(directory));
00336
00337 if (printing)
00338 printf("'%s' requested\n", directory);
00339 len = strlen(directory);
00340
00341 for (ui = 0;
00342 ui < len && directory[ui] != '\0' && isspace(directory[ui]);
00343 ui++);
00344
00345 char *dirStr = new char[len + 3];
00346
00347
00348 strncpy(dirStr, directory, len - ui);
00349
00350 dirStr[len - ui] = '\0';
00351
00352 if (dirStr[0] == '/' || dirStr[0] == '~' ||
00353 dirStr[0] == '\\' || strstr(dirStr, "..") != NULL)
00354 {
00355 ArLog::log(ArLog::Normal, "ArServerFileLister: '%s' tried to access outside allowed area", dirStr);
00356 delete[] dirStr;
00357 sendPacket.uByte2ToBuf(1);
00358
00359 sendPacket.strToBuf(directory);
00360 if (client != NULL)
00361 client->sendPacketTcp(&sendPacket);
00362 return;
00363 }
00364
00365
00366 if (strlen(dirStr) > 0)
00367 {
00368
00369 ArUtil::appendSlash(dirStr, len + 2);
00370
00371 ArUtil::fixSlashes(dirStr, len + 2);
00372 }
00373
00374
00375 std::string wholeDir;
00376 wholeDir = myBaseDir;
00377 wholeDir += dirStr;
00378
00379 DIR *dir;
00380 struct dirent *ent;
00381 struct stat statBuf;
00382 std::set<std::string, ArStrCaseCmpOp> dirs;
00383 std::map<std::string, ArTypes::UByte4> dirToATime;
00384 std::map<std::string, ArTypes::UByte4> dirToMTime;
00385 std::map<std::string, ArTypes::UByte4> dirToSize;
00386 std::set<std::string, ArStrCaseCmpOp> files;
00387 std::map<std::string, ArTypes::UByte4> fileToATime;
00388 std::map<std::string, ArTypes::UByte4> fileToMTime;
00389 std::map<std::string, ArTypes::UByte4> fileToSize;
00390 std::set<std::string, ArStrCaseCmpOp>::iterator it;
00391 std::string str;
00392
00393 if ((dir = opendir(wholeDir.c_str())) == NULL)
00394 {
00395 ArLog::log(ArLog::Normal, "ArServerFileLister: No such directory '%s' from base '%s' plus directory '%s'",
00396 directory, myBaseDir, dirStr);
00397 delete[] dirStr;
00398 sendPacket.uByte2ToBuf(2);
00399
00400 sendPacket.strToBuf(directory);
00401 if (client != NULL)
00402 client->sendPacketTcp(&sendPacket);
00403 return;
00404 }
00405 while ((ent = readdir(dir)) != NULL)
00406 {
00407
00408 if ((it = dirs.find(ent->d_name)) != dirs.end() ||
00409 (it = files.find(ent->d_name)) != files.end())
00410 {
00411 ArLog::log(ArLog::Normal,
00412 "ArServerFileLister: %s duplicates '%s'",
00413 ent->d_name, (*it).c_str());
00414 continue;
00415 }
00416 if (ent->d_name[0] == '.')
00417 continue;
00418 str = wholeDir.c_str();
00419 str += ent->d_name;
00420 if (printing)
00421 printf("name %s\n", str.c_str());
00422 if (stat(str.c_str(), &statBuf) == 0)
00423 {
00424 if (S_ISREG(statBuf.st_mode))
00425 {
00426 files.insert(ent->d_name);
00427 fileToATime[ent->d_name] = statBuf.st_atime;
00428 fileToMTime[ent->d_name] = statBuf.st_mtime;
00429 fileToSize[ent->d_name] = statBuf.st_size;
00430
00431 }
00432 if (S_ISDIR(statBuf.st_mode))
00433 {
00434 dirs.insert(ent->d_name);
00435 dirToATime[ent->d_name] = statBuf.st_atime;
00436 dirToMTime[ent->d_name] = statBuf.st_mtime;
00437 dirToSize[ent->d_name] = statBuf.st_size;
00438
00439 }
00440 }
00441 else
00442 {
00443 ArLog::log(ArLog::Normal, "Cannot stat %s in %s", ent->d_name, wholeDir.c_str());
00444 }
00445 }
00446
00447 sendPacket.uByte2ToBuf(0);
00448
00449 sendPacket.strToBuf(directory);
00450 if (printing)
00451 printf("Sending %s\n", directory);
00452 if (printing)
00453 printf("Dirs:\n");
00454
00455 sendPacket.uByte2ToBuf(dirs.size());
00456 for (it = dirs.begin(); it != dirs.end(); it++)
00457 {
00458 sendPacket.strToBuf((*it).c_str());
00459 sendPacket.uByte4ToBuf(dirToATime[(*it)]);
00460 sendPacket.uByte4ToBuf(dirToMTime[(*it)]);
00461 sendPacket.uByte4ToBuf(dirToSize[(*it)]);
00462
00463 }
00464
00465 if (printing)
00466 {
00467 printf("\n");
00468 printf("Files:\n");
00469 }
00470 sendPacket.uByte2ToBuf(files.size());
00471 for (it = files.begin(); it != files.end(); it++)
00472 {
00473 sendPacket.strToBuf((*it).c_str());
00474 sendPacket.uByte4ToBuf(fileToATime[(*it)]);
00475 sendPacket.uByte4ToBuf(fileToMTime[(*it)]);
00476 sendPacket.uByte4ToBuf(fileToSize[(*it)]);
00477 if (printing)
00478 {
00479 time_t atime = fileToATime[(*it)];
00480 time_t mtime = fileToMTime[(*it)];
00481 printf("\tname: %s\n", (*it).c_str());
00482 printf("\t\tlastAccessed: %s", ctime(&atime));
00483 printf("\t\tlastModified: %s", ctime(&mtime));
00484 printf("\t\tsize: %d", fileToSize[(*it)]);
00485 }
00486 }
00487 delete[] dirStr;
00488 if (client != NULL)
00489 client->sendPacketTcp(&sendPacket);
00490 }
00491
00492
00493 AREXPORT ArServerFileToClient::ArServerFileToClient(ArServerBase *server,
00494 const char *topDir) :
00495 myGetFileCB(this, &ArServerFileToClient::getFile)
00496 {
00497 myServer = server;
00498 myServer->addData("getFile",
00499 "Gets a file (use ArClientFileToClient instead of calling this directly since this interface may change)",
00500 &myGetFileCB, "string: file to get; byte2: operation, 0 == get, 1 == cancel (these aren't implemented yet but will be)",
00501 "ubyte2: return code, 0 = good (sending file), 1 = tried to go outside allowed area, 2 = no such file (or can't read), 3 = empty file name, 4 = error reading file (can happen after some good values) ; string: fileGotten;IF return was 0 then ubyte4: numBytes (number of bytes in this packet, 0 means end of file; numBytes of data",
00502 "FileAccess", "RETURN_UNTIL_EMPTY");
00503
00504
00505 strncpy(myBaseDir, topDir, sizeof(myBaseDir) - 2);
00506 myBaseDir[sizeof(myBaseDir) - 2] = '\0';
00507
00508 ArUtil::appendSlash(myBaseDir, sizeof(myBaseDir));
00509
00510 ArUtil::fixSlashes(myBaseDir, sizeof(myBaseDir));
00511 }
00512
00513 AREXPORT ArServerFileToClient::~ArServerFileToClient()
00514 {
00515
00516 }
00517
00518
00519
00520 AREXPORT void ArServerFileToClient::getFile(ArServerClient *client,
00521 ArNetPacket *packet)
00522 {
00523 ArNetPacket sendPacket;
00524 size_t ui;
00525 size_t len;
00526
00527 char fileNameRaw[2048];
00528 packet->bufToStr(fileNameRaw, sizeof(fileNameRaw));
00529
00530
00531
00532 char fileNameCooked[2048];
00533 strcpy(fileNameCooked, fileNameRaw);
00534 ArUtil::fixSlashes(fileNameCooked, sizeof(fileNameCooked));
00535
00536
00537 char fileName[2048];
00538 if (!ArServerFileUtil::squashCase(myBaseDir, fileNameCooked,
00539 fileName, sizeof(fileName)))
00540 {
00541 ArLog::log(ArLog::Normal,
00542 "ArServerFileToClient: can't open file '%s'", fileNameRaw);
00543 sendPacket.uByte2ToBuf(2);
00544 sendPacket.strToBuf(fileNameRaw);
00545 client->sendPacketTcp(&sendPacket);
00546
00547 sendPacket.empty();
00548 client->sendPacketTcp(&sendPacket);
00549 return;
00550 }
00551
00552 len = strlen(fileName);
00553
00554 for (ui = 0;
00555 ui < len && fileName[ui] != '\0' && isspace(fileName[ui]);
00556 ui++);
00557
00558 char *fileStr = new char[len + 3];
00559
00560
00561 strncpy(fileStr, fileName, len - ui);
00562
00563 fileStr[len - ui] = '\0';
00564
00565 if (fileStr[0] == '/' || fileStr[0] == '~' ||
00566 fileStr[0] == '\\' || strstr(fileStr, "..") != NULL)
00567 {
00568 ArLog::log(ArLog::Normal,
00569 "ArServerFileToClient: '%s' tried to access outside allowed area",
00570 fileStr);
00571 delete[] fileStr;
00572 sendPacket.uByte2ToBuf(1);
00573 sendPacket.strToBuf(fileNameRaw);
00574 client->sendPacketTcp(&sendPacket);
00575
00576 sendPacket.empty();
00577 client->sendPacketTcp(&sendPacket);
00578 return;
00579 }
00580
00581 if (strlen(fileStr) > 0)
00582 {
00583 ArUtil::fixSlashes(fileStr, len + 2);
00584 }
00585 else
00586 {
00587 ArLog::log(ArLog::Normal,
00588 "ArServerFileToClient: can't get file, empty filename");
00589 delete[] fileStr;
00590 sendPacket.uByte2ToBuf(3);
00591 sendPacket.strToBuf(fileNameRaw);
00592 client->sendPacketTcp(&sendPacket);
00593
00594 sendPacket.empty();
00595 client->sendPacketTcp(&sendPacket);
00596 return;
00597 }
00598
00599
00600
00601
00602
00603 std::string wholeName;
00604 wholeName = myBaseDir;
00605 wholeName += fileStr;
00606
00607 delete[] fileStr;
00608
00609 ArLog::log(ArLog::Verbose,
00610 "ArServerFileToClient: Trying to open %s from base %s",
00611 wholeName.c_str(), myBaseDir);
00612 FILE *file;
00613 if ((file = fopen(wholeName.c_str(), "rb")) == NULL)
00614 {
00615 ArLog::log(ArLog::Normal,
00616 "ArServerFileToClient: can't open file '%s'", fileName);
00617 sendPacket.uByte2ToBuf(2);
00618 sendPacket.strToBuf(fileNameRaw);
00619 client->sendPacketTcp(&sendPacket);
00620
00621 sendPacket.empty();
00622 client->sendPacketTcp(&sendPacket);
00623 return;
00624 }
00625
00626
00627 char buf[30000];
00628 size_t ret;
00629
00630 while ((ret = fread(buf, 1, sizeof(buf), file)) == sizeof(buf))
00631 {
00632 sendPacket.empty();
00633 sendPacket.uByte2ToBuf(0);
00634 sendPacket.strToBuf(fileNameRaw);
00635 sendPacket.uByte4ToBuf(ret);
00636 sendPacket.dataToBuf(buf, ret);
00637 client->sendPacketTcp(&sendPacket);
00638
00639 }
00640 if (ferror(file))
00641 {
00642 ArLog::log(ArLog::Normal, "ArServerFileToClient: Error sending file %s",
00643 fileName);
00644 sendPacket.empty();
00645 sendPacket.uByte2ToBuf(4);
00646 sendPacket.strToBuf(fileNameRaw);
00647 client->sendPacketTcp(&sendPacket);
00648
00649 sendPacket.empty();
00650 client->sendPacketTcp(&sendPacket);
00651 return;
00652 }
00653
00654 sendPacket.empty();
00655 sendPacket.uByte2ToBuf(0);
00656 sendPacket.strToBuf(fileNameRaw);
00657 sendPacket.uByte4ToBuf(ret);
00658 sendPacket.dataToBuf(buf, ret);
00659
00660 client->sendPacketTcp(&sendPacket);
00661
00662
00663
00664 if (ret != 0)
00665 {
00666 sendPacket.empty();
00667 sendPacket.uByte2ToBuf(0);
00668 sendPacket.strToBuf(fileNameRaw);
00669 sendPacket.uByte4ToBuf(0);
00670
00671 client->sendPacketTcp(&sendPacket);
00672 }
00673
00674 sendPacket.empty();
00675 client->sendPacketTcp(&sendPacket);
00676
00677 fclose(file);
00678 if (feof(file))
00679 {
00680 ArLog::log(ArLog::Normal, "ArServerFileToClient: Sent file %s to %s",
00681 fileName, client->getIPString());
00682 }
00683 }
00684
00685 AREXPORT ArServerFileFromClient::ArServerFileFromClient(ArServerBase *server,
00686 const char *topDir,
00687 const char *tempDir) :
00688 myPutFileCB(this, &ArServerFileFromClient::putFile),
00689 myPutFileInterleavedCB(this, &ArServerFileFromClient::putFileInterleaved)
00690 {
00691 myServer = server;
00692 myServer->addData("putFile",
00693 "Puts a file (use ArClientFileFromClient instead of calling this directly since this interface may change)",
00694 &myPutFileCB, "uByte2: command, 0 = start file, 1 = continue file, 2 done with file, 3 = cancel put; string: file being sent; IF command == 1 then uByte4: numBytes; numBytes of data",
00695 "uByte2: return code, 0 = good (got file), 1 = getting file, 2 = tried to go outside allowed area, 3 = bad directory, 4 = empty file name (or other problem with fileName), 5 = can't write temp file, 6 = error moving file from temp to perm, 7 = another client putting file, 8 = timeout (no activity for 15 seconds) and another client wanted to put the file, 9 = client adding to, finishing, or canceling a file the server doesn't have; string: fileName",
00696 "FileAccess", "RETURN_COMPLEX");
00697
00698 myServer->addData("putFileInterleaved",
00699 "Puts a file (use ArClientFileFromClient instead of calling this directly since this interface may change)",
00700 &myPutFileInterleavedCB, "uByte2: command, 0 = start file, 1 = continue file, 2 done with file, 3 = cancel put; string: file being sent; IF command == 1 then uByte4: numBytes; numBytes of data",
00701 "uByte2: return code, 0 = good (got file), 1 = getting file, 2 = tried to go outside allowed area, 3 = bad directory, 4 = empty file name (or other problem with fileName), 5 = can't write temp file, 6 = error moving file from temp to perm, 7 = another client putting file, 8 = timeout (no activity for 15 seconds) and another client wanted to put the file, 9 = client adding to, finishing, or canceling a file the server doesn't have, 10 = gotPacket, awaiting next packet, 11 = cancelled put; string: fileName",
00702 "FileAccess", "RETURN_SINGLE");
00703
00704 myFileNumber = 0;
00705
00706 strncpy(myBaseDir, topDir, sizeof(myBaseDir) - 2);
00707 myBaseDir[sizeof(myBaseDir) - 2] = '\0';
00708
00709 ArUtil::appendSlash(myBaseDir, sizeof(myBaseDir));
00710
00711 ArUtil::fixSlashes(myBaseDir, sizeof(myBaseDir));
00712
00713 strncpy(myTempDir, tempDir, sizeof(myTempDir) - 2);
00714 myTempDir[sizeof(myTempDir) - 2] = '\0';
00715
00716 ArUtil::appendSlash(myTempDir, sizeof(myTempDir));
00717
00718 ArUtil::fixSlashes(myTempDir, sizeof(myTempDir));
00719 }
00720
00721 AREXPORT ArServerFileFromClient::~ArServerFileFromClient()
00722 {
00723
00724 }
00725
00726
00727 AREXPORT void ArServerFileFromClient::putFile(ArServerClient *client,
00728 ArNetPacket *packet)
00729 {
00730 internalPutFile(client, packet, false);
00731 }
00732
00733 AREXPORT void ArServerFileFromClient::putFileInterleaved(
00734 ArServerClient *client, ArNetPacket *packet)
00735 {
00736 internalPutFile(client, packet, true);
00737 }
00738
00739 AREXPORT void ArServerFileFromClient::internalPutFile(ArServerClient *client,
00740 ArNetPacket *packet,
00741 bool interleaved)
00742 {
00743 ArNetPacket sendPacket;
00744 std::list<ArFunctor *>::iterator fit;
00745 std::map<std::string, FileInfo *>::iterator it;
00746 FileInfo *info;
00747 std::string fileName;
00748 char fileNameRaw[2048];
00749 fileNameRaw[0] = '\0';
00750 ArTypes::UByte2 doing;
00751 doing = packet->bufToUByte2();
00752 packet->bufToStr(fileNameRaw, sizeof(fileNameRaw));
00753 if (doing == 0)
00754 {
00755 char directoryRaw[2048];
00756 directoryRaw[0] = '\0';
00757 char fileNamePart[2048];
00758 fileNamePart[0] = '\0';
00759 if (!ArServerFileUtil::getDirectory(fileNameRaw,
00760 directoryRaw, sizeof(directoryRaw)) ||
00761 !ArServerFileUtil::getFileName(fileNameRaw,
00762 fileNamePart, sizeof(fileNamePart)))
00763 {
00764 ArLog::log(ArLog::Normal,
00765 "ArServerFileFromClient: Problem with filename '%s'",
00766 fileNameRaw);
00767 sendPacket.uByte2ToBuf(4);
00768 sendPacket.strToBuf(fileNameRaw);
00769 client->sendPacketTcp(&sendPacket);
00770
00771 return;
00772 }
00773
00774 char directory[2048];
00775 printf("DirectoryRaw %s\n", directoryRaw);
00776 if (strlen(directoryRaw) == 0)
00777 {
00778 strcpy(directory, ".");
00779 }
00780 else if (!ArServerFileUtil::squashCase(myBaseDir, directoryRaw, directory,
00781 sizeof(directory)))
00782 {
00783 ArLog::log(ArLog::Normal,
00784 "ArServerFileFromClient: Bad directory for '%s'",
00785 fileNameRaw);
00786 sendPacket.uByte2ToBuf(3);
00787 sendPacket.strToBuf(fileNameRaw);
00788 client->sendPacketTcp(&sendPacket);
00789 return;
00790 }
00791
00792 char tmpDir[2048];
00793 tmpDir[0] = '\0';
00794
00795 strcpy(tmpDir, directory);
00796 ArUtil::appendSlash(tmpDir, sizeof(tmpDir));
00797 char squashedFileName[2048];
00798
00799 if (ArServerFileUtil::squashCase(tmpDir, fileNamePart,
00800 squashedFileName,
00801 sizeof(squashedFileName)))
00802 {
00803 fileName = tmpDir;
00804 fileName += squashedFileName;
00805
00806 }
00807 else
00808 {
00809 fileName = tmpDir;
00810 fileName += fileNamePart;
00811
00812 }
00813
00814 ArLog::log(ArLog::Normal,
00815 "ArServerFileFromClient: Checking file %s (as %s)",
00816 fileNameRaw, fileName.c_str());
00817 for (it = myMap.begin(); it != myMap.end(); it++)
00818 {
00819 info = (*it).second;
00820
00821 if (ArUtil::strcasecmp(info->myRealFileName, fileName) == 0)
00822 {
00823
00824 if (info->myLastActivity.secSince() > 15)
00825 {
00826 ArLog::log(ArLog::Normal,
00827 "ArServerFileFromClient: Another client wants to start putting file '%s' and old client was inactive",
00828 (*it).first.c_str());
00829 if (!interleaved)
00830 {
00831 sendPacket.uByte2ToBuf(8);
00832 sendPacket.strToBuf((*it).first.c_str());
00833
00834
00835
00836
00837 myServer->broadcastPacketTcp(&sendPacket, "putFile");
00838 }
00839 myMap.erase((*it).first);
00840 delete info;
00841 break;
00842 }
00843
00844 else
00845 {
00846 ArLog::log(ArLog::Normal,
00847 "ArServerFileFromClient: Another client putting file '%s'",
00848 fileNameRaw);
00849 sendPacket.uByte2ToBuf(7);
00850 sendPacket.strToBuf(fileNameRaw);
00851 client->sendPacketTcp(&sendPacket);
00852 return;
00853 }
00854 }
00855 }
00856 ArLog::log(ArLog::Normal,
00857 "ArServerFileFromClient: Receiving file %s (as %s)",
00858 fileNameRaw, fileName.c_str());
00859 char tempFileName[3200];
00860 tempFileName[0] = '\0';
00861 sprintf(tempFileName, "%sArServerFileFromClient.%d.%d", myTempDir, getpid(), myFileNumber);
00862 myFileNumber++;
00863
00864 printf("Using temp file name %s\n", tempFileName);
00865
00866 FILE *file;
00867 if ((file = fopen(tempFileName, "wb")) != NULL)
00868 {
00869 info = new FileInfo;
00870 info->myRealFileName = fileName;
00871 info->myTempFileName = tempFileName;
00872 info->myFile = file;
00873 info->myStartedTransfer.setToNow();
00874 info->myLastActivity.setToNow();
00875 myMap[fileNameRaw] = info;
00876 if (interleaved)
00877 {
00878
00879 sendPacket.uByte2ToBuf(10);
00880 sendPacket.strToBuf(fileNameRaw);
00881 client->sendPacketTcp(&sendPacket);
00882 }
00883 }
00884 else
00885 {
00886 ArLog::log(ArLog::Normal,
00887 "ArServerFileFromClient: Can't open tmp file for '%s' (tried '%s')",
00888 fileNameRaw, tempFileName);
00889 sendPacket.uByte2ToBuf(5);
00890 sendPacket.strToBuf(fileNameRaw);
00891 client->sendPacketTcp(&sendPacket);
00892 return;
00893 }
00894 }
00895 else if (doing == 1)
00896 {
00897
00898 if ((it = myMap.find(fileNameRaw)) == myMap.end())
00899 {
00900 ArLog::log(ArLog::Normal, "ArServerFileUtil: Couldn't find entry for '%s'", fileNameRaw);
00901 sendPacket.uByte2ToBuf(9);
00902 sendPacket.strToBuf(fileNameRaw);
00903 client->sendPacketTcp(&sendPacket);
00904 return;
00905 }
00906 info = (*it).second;
00907
00908 ArTypes::UByte4 numBytes;
00909 char buf[32000];
00910 numBytes = packet->bufToUByte4();
00911 packet->bufToData(buf, numBytes);
00912 fwrite(buf, 1, numBytes, info->myFile);
00913 info->myLastActivity.setToNow();
00914 if (interleaved)
00915 {
00916 sendPacket.uByte2ToBuf(10);
00917 sendPacket.strToBuf(fileNameRaw);
00918 client->sendPacketTcp(&sendPacket);
00919 }
00920 ArLog::log(ArLog::Verbose, "Continuing put file %s (%d bytes)",
00921 fileNameRaw, numBytes);
00922
00923 }
00924 else if (doing == 2)
00925 {
00926
00927 if ((it = myMap.find(fileNameRaw)) == myMap.end())
00928 {
00929 ArLog::log(ArLog::Normal, "ArServerFileUtil: Couldn't find entry for '%s'", fileNameRaw);
00930 sendPacket.uByte2ToBuf(9);
00931 sendPacket.strToBuf(fileNameRaw);
00932 client->sendPacketTcp(&sendPacket);
00933 return;
00934 }
00935 info = (*it).second;
00936 fclose(info->myFile);
00937 info->myFile = NULL;
00938
00939 char systemBuf[6400];
00940 #ifndef WIN32
00941 char *mvName = "mv";
00942 #else
00943 char *mvName = "move";
00944 #endif
00945 sprintf(systemBuf, "%s \"%s\" \"%s\"", mvName, info->myTempFileName.c_str(),
00946 info->myRealFileName.c_str());
00947
00948
00949 myMovingFileName = info->myRealFileName;
00950
00951
00952 for (fit = myPreMoveCallbacks.begin();
00953 fit != myPreMoveCallbacks.end();
00954 fit++)
00955 (*fit)->invoke();
00956
00957
00958 int ret;
00959 if ((ret = system(systemBuf)) == 0)
00960 {
00961 sendPacket.uByte2ToBuf(0);
00962 sendPacket.strToBuf(fileNameRaw);
00963 client->sendPacketTcp(&sendPacket);
00964 ArLog::log(ArLog::Normal, "Done with file %s from %s", fileNameRaw,
00965 client->getIPString());
00966 myMap.erase((*it).first);
00967 delete info;
00968 }
00969 else
00970 {
00971 sendPacket.uByte2ToBuf(6);
00972 sendPacket.strToBuf(fileNameRaw);
00973 client->sendPacketTcp(&sendPacket);
00974 unlink(info->myTempFileName.c_str());
00975 myMap.erase((*it).first);
00976 delete info;
00977 ArLog::log(ArLog::Normal, "Couldn't move temp file for %s (ret of '%s' is %d)", fileNameRaw, systemBuf, ret);
00978 }
00979
00980
00981 for (fit = myPostMoveCallbacks.begin();
00982 fit != myPostMoveCallbacks.end();
00983 fit++)
00984 (*fit)->invoke();
00985
00986 myMovingFileName = "";
00987 }
00988 else if (doing == 3)
00989 {
00990 if ((it = myMap.find(fileNameRaw)) == myMap.end())
00991 {
00992 ArLog::log(ArLog::Normal, "ArServerFileUtil: Couldn't find entry to cancel for '%s'", fileNameRaw);
00993 sendPacket.uByte2ToBuf(9);
00994 sendPacket.strToBuf(fileNameRaw);
00995 client->sendPacketTcp(&sendPacket);
00996 return;
00997 }
00998 info = (*it).second;
00999 fclose(info->myFile);
01000 info->myFile = NULL;
01001
01002 unlink(info->myTempFileName.c_str());
01003 myMap.erase((*it).first);
01004 delete info;
01005
01006 ArLog::log(ArLog::Normal, "Cancelling file %s", fileNameRaw);
01007 if (interleaved)
01008 {
01009 sendPacket.uByte2ToBuf(11);
01010 sendPacket.strToBuf(fileNameRaw);
01011 client->sendPacketTcp(&sendPacket);
01012 }
01013 }
01014 else
01015 {
01016 ArLog::log(ArLog::Normal, "Unknown command %d for file %s", doing,
01017 fileNameRaw);
01018 }
01019 }
01020
01021 AREXPORT void ArServerFileFromClient::addPreMoveCallback(
01022 ArFunctor *functor, ArListPos::Pos position)
01023 {
01024 if (position == ArListPos::FIRST)
01025 myPreMoveCallbacks.push_front(functor);
01026 else if (position == ArListPos::LAST)
01027 myPreMoveCallbacks.push_back(functor);
01028 else
01029 ArLog::log(ArLog::Terse,
01030 "ArServerFileFromClient::addPreMoveCallback: Invalid position.");
01031 }
01032
01033 AREXPORT void ArServerFileFromClient::remPreMoveCallback(
01034 ArFunctor *functor)
01035 {
01036 myPreMoveCallbacks.remove(functor);
01037 }
01038
01039 AREXPORT void ArServerFileFromClient::addPostMoveCallback(
01040 ArFunctor *functor, ArListPos::Pos position)
01041 {
01042 if (position == ArListPos::FIRST)
01043 myPostMoveCallbacks.push_front(functor);
01044 else if (position == ArListPos::LAST)
01045 myPostMoveCallbacks.push_back(functor);
01046 else
01047 ArLog::log(ArLog::Terse,
01048 "ArServerFileFromClient::addPostMoveCallback: Invalid position.");
01049 }
01050
01051 AREXPORT void ArServerFileFromClient::remPostMoveCallback(
01052 ArFunctor *functor)
01053 {
01054 myPostMoveCallbacks.remove(functor);
01055 }
01056
01057
01058 AREXPORT ArServerDeleteFileOnServer::ArServerDeleteFileOnServer(
01059 ArServerBase *server, const char *topDir) :
01060 myDeleteFileCB(this, &ArServerDeleteFileOnServer::deleteFile)
01061 {
01062 myServer = server;
01063 myServer->addData("deleteFile",
01064 "Deletes a file (use ArClientDeleteFileOnServer instead of calling this directly since this interface may change)",
01065 &myDeleteFileCB, "string: file to delete",
01066 "ubyte2: return code, 0 = good (deleted file file), 1 = tried to go outside allowed area, 2 = no such file (or can't read it), 3 = empty file name, string: fileDeleted",
01067 "FileAccess", "RETURN_SINGLE");
01068
01069
01070 strncpy(myBaseDir, topDir, sizeof(myBaseDir) - 2);
01071 myBaseDir[sizeof(myBaseDir) - 2] = '\0';
01072
01073 ArUtil::appendSlash(myBaseDir, sizeof(myBaseDir));
01074
01075 ArUtil::fixSlashes(myBaseDir, sizeof(myBaseDir));
01076 }
01077
01078 AREXPORT ArServerDeleteFileOnServer::~ArServerDeleteFileOnServer()
01079 {
01080
01081 }
01082
01083
01084
01085 AREXPORT void ArServerDeleteFileOnServer::deleteFile(ArServerClient *client,
01086 ArNetPacket *packet)
01087 {
01088 ArNetPacket sendPacket;
01089 size_t ui;
01090 size_t len;
01091 std::list<ArFunctor *>::iterator fit;
01092 char fileNameRaw[2048];
01093 packet->bufToStr(fileNameRaw, sizeof(fileNameRaw));
01094
01095
01096
01097 char fileNameCooked[2048];
01098 strcpy(fileNameCooked, fileNameRaw);
01099 ArUtil::fixSlashes(fileNameCooked, sizeof(fileNameCooked));
01100
01101
01102 char fileName[2048];
01103 if (!ArServerFileUtil::squashCase(myBaseDir, fileNameCooked,
01104 fileName, sizeof(fileName)))
01105 {
01106 ArLog::log(ArLog::Normal,
01107 "ArServerDeleteFileOnServer: can't read file '%s'",
01108 fileNameRaw);
01109 sendPacket.uByte2ToBuf(2);
01110 sendPacket.strToBuf(fileNameRaw);
01111 client->sendPacketTcp(&sendPacket);
01112 return;
01113 }
01114
01115 len = strlen(fileName);
01116
01117 for (ui = 0;
01118 ui < len && fileName[ui] != '\0' && isspace(fileName[ui]);
01119 ui++);
01120
01121 char *fileStr = new char[len + 3];
01122
01123
01124 strncpy(fileStr, fileName, len - ui);
01125
01126 fileStr[len - ui] = '\0';
01127
01128 if (fileStr[0] == '/' || fileStr[0] == '~' ||
01129 fileStr[0] == '\\' || strstr(fileStr, "..") != NULL)
01130 {
01131 ArLog::log(ArLog::Normal,
01132 "ArServerDeleteFileOnServer: '%s' tried to access outside allowed area",
01133 fileStr);
01134 delete[] fileStr;
01135 sendPacket.uByte2ToBuf(1);
01136 sendPacket.strToBuf(fileNameRaw);
01137 client->sendPacketTcp(&sendPacket);
01138 return;
01139 }
01140
01141 if (strlen(fileStr) > 0)
01142 {
01143 ArUtil::fixSlashes(fileStr, len + 2);
01144 }
01145 else
01146 {
01147 ArLog::log(ArLog::Normal,
01148 "ArServerDeleteFileOnServer: can't delete file, empty filename");
01149 delete[] fileStr;
01150 sendPacket.uByte2ToBuf(3);
01151 sendPacket.strToBuf(fileNameRaw);
01152 client->sendPacketTcp(&sendPacket);
01153 return;
01154 }
01155
01156
01157
01158
01159
01160 std::string wholeName;
01161 wholeName = myBaseDir;
01162 wholeName += fileStr;
01163
01164 delete[] fileStr;
01165
01166 ArLog::log(ArLog::Verbose,
01167 "ArServerDeleteFileOnServer: Trying to delete %s from base %s",
01168 wholeName.c_str(), myBaseDir);
01169
01170 myDeletingFileName = fileNameRaw;
01171
01172
01173 for (fit = myPreDeleteCallbacks.begin();
01174 fit != myPreDeleteCallbacks.end();
01175 fit++)
01176 (*fit)->invoke();
01177
01178 if (unlink(wholeName.c_str()) == 0)
01179 {
01180 ArLog::log(ArLog::Normal,
01181 "ArServerDeleteFileOnServer: Deleted file %s for %s",
01182 fileName, client->getIPString());
01183 sendPacket.uByte2ToBuf(0);
01184 sendPacket.strToBuf(fileNameRaw);
01185 client->sendPacketTcp(&sendPacket);
01186 }
01187 else
01188 {
01189 ArLog::log(ArLog::Normal,
01190 "ArServerDeleteFileOnServer: can't unlink file '%s'", fileName);
01191 sendPacket.uByte2ToBuf(2);
01192 sendPacket.strToBuf(fileNameRaw);
01193 client->sendPacketTcp(&sendPacket);
01194 }
01195
01196
01197 for (fit = myPostDeleteCallbacks.begin();
01198 fit != myPostDeleteCallbacks.end();
01199 fit++)
01200 (*fit)->invoke();
01201
01202 myDeletingFileName = "";
01203 }
01204
01205 AREXPORT void ArServerDeleteFileOnServer::addPreDeleteCallback(
01206 ArFunctor *functor, ArListPos::Pos position)
01207 {
01208 if (position == ArListPos::FIRST)
01209 myPreDeleteCallbacks.push_front(functor);
01210 else if (position == ArListPos::LAST)
01211 myPreDeleteCallbacks.push_back(functor);
01212 else
01213 ArLog::log(ArLog::Terse,
01214 "ArServerDeleteFileOnServer::addPreDeleteCallback: Invalid position.");
01215 }
01216
01217 AREXPORT void ArServerDeleteFileOnServer::remPreDeleteCallback(
01218 ArFunctor *functor)
01219 {
01220 myPreDeleteCallbacks.remove(functor);
01221 }
01222
01223 AREXPORT void ArServerDeleteFileOnServer::addPostDeleteCallback(
01224 ArFunctor *functor, ArListPos::Pos position)
01225 {
01226 if (position == ArListPos::FIRST)
01227 myPostDeleteCallbacks.push_front(functor);
01228 else if (position == ArListPos::LAST)
01229 myPostDeleteCallbacks.push_back(functor);
01230 else
01231 ArLog::log(ArLog::Terse,
01232 "ArServerDeleteFileOnServer::addPostDeleteCallback: Invalid position.");
01233 }
01234
01235 AREXPORT void ArServerDeleteFileOnServer::remPostDeleteCallback(
01236 ArFunctor *functor)
01237 {
01238 myPostDeleteCallbacks.remove(functor);
01239 }
01240
01241 #endif // WIN32