/** * Iterate through the directory. Remove any file found, save any found directory * Any attempt to delete files from "/"or "/root" will be ignored. * * * @param location to delete files from * @param return by reference number of files deleted * @param return by reference any found directory * @return whether or not all the operations were successful */ Result<bool> CleanDirectoryOfFileContents(const std::string& location , size_t& filesRemoved, std::vector<std::string>& foundDirectories) { if (("/" == location) || ("/root" == location) || ("/root/" == location)) { return Result<bool>{false, {"Not allowed to remove directory: " + location}}; } if (location.empty() || !FileIO::DoesDirectoryExist(location)) { return Result<bool>{false, {"Directory does not exist. False location was: " + location}}; } FileIO::DirectoryReader reader(location); if (reader.Valid().HasFailed()) { return Result<bool>{false, {"Failed to read directory: " + location + ". Error: " + reader.Valid().error}};; } FileIO::DirectoryReader::Entry entry; size_t failures{0}; filesRemoved = 0; std::string lastError; do { entry = reader.Next(); if (FileIO::FileType::Directory == entry.first) { std::string dirPath{location}; if ('/' != location.back()) { dirPath.append("/"); } dirPath.append(entry.second); foundDirectories.push_back(dirPath); } else if (FileIO::FileType::File == entry.first) { const std::string pathToFile{location + "/" + entry.second}; bool removedFile = (0 == unlink(pathToFile.c_str())); if (removedFile) { filesRemoved++; } else { ++failures; lastError = {"Last Error for file: " + pathToFile + ", errno: " }; lastError.append(std::strerror(errno)); } } // FileIO::FileSystem::Unknown is ignored } while (!Interrupted() && entry.first != FileIO::FileType::End); std::string report; if (failures > 0) { report = {"#" + std::to_string(failures) + " number of failed removals. " + lastError}; } return Result<bool>{(0 == failures), report}; }
/** * Move a file to another location. This works across device boundaries contrary to * 'rename' * * @return true if moved successfully and deleted the previous file successfully * false if move fail or the original file could not be deleted. For all failure * cases errno will be set * * Reference: * http://linux.die.net/man/3/rename * http://linux.die.net/man/3/open * http://www.lehman.cuny.edu/cgi-bin/man-cgi?sendfile+3 * * Performance sendfile vs user-level copy: * http://stackoverflow.com/questions/10195343/copy-a-file-in-an-sane-safe-and-efficient-way */ bool MoveFile(const std::string& sourcePath, const std::string& destPath) { if (!DoesFileExist(sourcePath) || sourcePath == destPath) { return false; // DoesFileExist sets errno: ENOENT i.e. No such file or directory } int64_t rc = rename(sourcePath.c_str(), destPath.c_str()); if (-1 == rc) { // On a separate device. Clear errno and try with sendfile errno = 0; ScopedFileDescriptor src(sourcePath, O_RDONLY, 0); struct stat stat_src; fstat(src.fd, &stat_src); const unsigned int permissions = stat_src.st_mode; ScopedFileDescriptor dest(destPath, O_WRONLY | O_CREAT, permissions); off_t offset = 0; // byte offset for sendfile // sendfile returns -1 for failure else number of bytes sent // sendfile can only move std::numeric_limits<int>::max() each time // i.e 2147483647 bytes (1.999... GB) // 'sendfile' is repeatedly called until all of the file is copied rc = sendfile(dest.fd, src.fd, &offset, stat_src.st_size); while (rc > 0 && rc < stat_src.st_size && !Interrupted()) { rc += sendfile(dest.fd, src.fd, &offset, stat_src.st_size); } // for certain file permissions unit testing gave that the permissions // were not preserved over the sendfile call. If this is the case // we re-set the same permissions as the original file had struct stat stat_dest; fstat(dest.fd, &stat_dest); int64_t rcStat = {0}; if (permissions != (stat_dest.st_mode & permissions)) { rcStat = chmod(destPath.c_str(), permissions); } if (-1 != rc && rc == stat_src.st_size && (0 == rcStat)) { rc = remove(sourcePath.c_str()); } } return (0 == rc); }
/** * Called when the command has been removed. * This will call {@link Command#interrupted() interrupted()} or {@link Command#end() end()}. */ void Command::Removed() { if (m_initialized) { if (IsCanceled()) { Interrupted(); _Interrupted(); } else { End(); _End(); } } m_initialized = false; m_canceled = false; m_running = false; if (m_table != NULL) m_table->PutBoolean(kRunning, false); }
//============================================================================= void Metaserver::Process() { SAIN clientAddr; socklen_t clientAddrLen = sizeof(clientAddr); unsigned char mesg[MAXLINE]; int bytes; SignalManager::GetInstance().RegisterHandler(SIGALRM, mSigalrmHandler); alarm(REAP_INTERVAL); for( ; ; ) { if(mSigintHandler->GetGracefulQuit()) Interrupted(); if(mSigalrmHandler->GetAlarm()) { mSigalrmHandler->SetAlarm(0); Reaper(); } if((bytes = recvfrom(mListenSocket, mesg, MAXLINE, 0, (SA *)&clientAddr, &clientAddrLen)) < 0) continue; NetMsg netmsg((const unsigned char *)mesg, bytes); switch(netmsg.GetType()) { case NMT_SERVERKEEPALIVE: { HandleServerKeepalive((SA *)&clientAddr, clientAddrLen); break; } case NMT_CLIENTKEEPALIVE: { HandleClientKeepalive((SA *)&clientAddr, clientAddrLen); break; } case NMT_SERVERSHAKE: { ServerShakeMsg msg(mesg, bytes); HandleServerShake((SA *)&clientAddr, msg); break; } case NMT_CLIENTSHAKE: { ClientShakeMsg msg(mesg, bytes); HandleClientShake((SA *)&clientAddr, msg); break; } case NMT_TERMINATE: { TerminateMsg msg(mesg, bytes); if(msg.Good()) { HandleTerminate((SA *)&clientAddr); } break; } case NMT_LISTREQ: { ListRequestMsg msg(mesg, bytes); if(msg.Good()) { HandleListRequest((SA *)&clientAddr, clientAddrLen, msg); } break; } case NMT_NULL: case NMT_HANDSHAKE: case NMT_LISTRESP: case NMT_PROTO_ERANGE: default: #ifdef DEBUG printf("Ignoring unknown message type: %d\n", netmsg.GetType()); #endif break; } mPacketCount++; } }
void TurboDriveOn::End(){Interrupted();} //the command should never actually End, but good practice just in case