void RequestHandler::renameFile()

in host/cxpslib/requesthandler.cpp [1369:1616]


void RequestHandler::renameFile()
{
    SCOPE_GUARD sessionLogoutGuard = MAKE_SCOPE_GUARD(boost::bind(&RequestHandler::sessionLogout, this));
    SCOPE_GUARD resetGuard = MAKE_SCOPE_GUARD(boost::bind(&RequestHandler::reset, this));

    m_requestTelemetryData.AcquiredRequestType(RequestType_RenameFile);

    if (!m_loggedIn) {
        m_requestTelemetryData.SetRequestFailure(RequestFailure_NotLoggedIn);
        badRequest(AT_LOC, "not logged in\n");
        return;
    }

    if (putFileInProgress(HTTP_REQUEST_RENAMEFILE)) {
        return;
    }

    tagValue_t::iterator oldNameTagValue(m_requestInfo.m_params.find(HTTP_PARAM_TAG_OLDNAME));

    if (m_requestInfo.m_params.end() == oldNameTagValue) {
        m_requestTelemetryData.SetRequestFailure(RequestFailure_MissingOldName);
        throw ERROR_EXCEPTION << "missing oldname";
    }

    if ((*oldNameTagValue).second.empty()) {
        m_requestTelemetryData.SetRequestFailure(RequestFailure_MissingOldName);
        throw ERROR_EXCEPTION << "missing original file name";
    }

    // Note that the file type determiniation would also work for all kinds of new file name as well.
    // TODO-SanKumar-1711: Assert FileTypeDetermined(OldFile) == FileTypeDetermined(NewFile)
    m_requestTelemetryData.AcquiredFilePath(oldNameTagValue->second);

    tagValue_t::iterator newNameTagValue(m_requestInfo.m_params.find(HTTP_PARAM_TAG_NEWNAME));
    if (m_requestInfo.m_params.end() == newNameTagValue) {
        m_requestTelemetryData.SetRequestFailure(RequestFailure_MissingNewName);
        throw ERROR_EXCEPTION << " missing newname";
    }

    if ((*newNameTagValue).second.empty()) {
        m_requestTelemetryData.SetRequestFailure(RequestFailure_MissingNewName);
        throw ERROR_EXCEPTION << "missing new file name";
    }

    std::string ver;
    if (!getVersion(ver)) {
        m_requestTelemetryData.SetRequestFailure(RequestFailure_MissingVer);
        badRequest(AT_LOC, "missing ver");
        return;
    }

    tagValue_t::iterator idTagValue(m_requestInfo.m_params.find(HTTP_PARAM_TAG_ID));
    if (m_requestInfo.m_params.end() == idTagValue) {
        m_requestTelemetryData.SetRequestFailure(RequestFailure_MissingId);
        throw ERROR_EXCEPTION << "missing id";
    }

    tagValue_t::iterator reqIdTagValue(m_requestInfo.m_params.find(HTTP_PARAM_TAG_REQ_ID));
    if (m_requestInfo.m_params.end() == reqIdTagValue) {
        m_requestTelemetryData.SetRequestFailure(RequestFailure_MissingReqId);
        throw ERROR_EXCEPTION << "missing reqid";
    }

    boost::uint32_t reqId = boost::lexical_cast<boost::uint32_t>((*reqIdTagValue).second);
    if (reqId <= m_reqId) {
        m_requestTelemetryData.SetRequestFailure(RequestFailure_InvalidReqId);
        throw ERROR_EXCEPTION << "invalid request id";
    }

    logRequestBegin();

    if (!Authentication::verifyRenameFileId(m_hostId,
                                            m_serverOptions->password(),
                                            HTTP_METHOD_GET,
                                            HTTP_REQUEST_RENAMEFILE,
                                            m_cnonce,
                                            m_sessionId,
                                            m_snonce,
                                            (*oldNameTagValue).second,
                                            (*newNameTagValue).second,
                                            ver,
                                            reqId,
                                            (*idTagValue).second)) {
        m_requestTelemetryData.SetRequestFailure(RequestFailure_VerifRenFile);

        std::string msg("invalid id for host: ");
        msg += m_hostId;
        msg += " request: ";
        msg += HTTP_REQUEST_RENAMEFILE;
        badRequest(AT_LOC, msg.c_str());
        return;
    }
    m_reqId = reqId;

    m_requestTelemetryData.StartingOp();

    tagValue_t::iterator appendMTimeUtcTagValue(m_requestInfo.m_params.find(HTTP_PARAM_TAG_APPENDMTIMEUTC));

    bool shouldAppendMTimeInUtc =
        (appendMTimeUtcTagValue != m_requestInfo.m_params.end()) &&
        (appendMTimeUtcTagValue->second == "1");

    tagValue_t::iterator finalPathsTagValue(m_requestInfo.m_params.find(HTTP_PARAM_TAG_FINAL_PATHS));

    std::replace((*oldNameTagValue).second.begin(), (*oldNameTagValue).second.end(), '\\', '/');
    std::replace((*newNameTagValue).second.begin(), (*newNameTagValue).second.end(), '\\', '/');

    std::string sessionId;
    try {
        boost::filesystem::path oldFullNamePath;
        getFullPathName((*oldNameTagValue).second, oldFullNamePath);
        extendedLengthPath_t extOldName(ExtendedLengthPath::name(oldFullNamePath.string()));
        if (!boost::filesystem::exists(extOldName)) {
            std::string str(oldFullNamePath.string() + "not found");
            sendError(ResponseCode::RESPONSE_NOT_FOUND, str.data(), str.length());
            m_requestTelemetryData.SuccessfullyResponded(); // Not a critical error.
            logRequestNotFound();
        } else {
            std::string sessionId = g_sessionTracker->checkOpenFile(oldFullNamePath, false, true);
            if (!sessionId.empty()) {
                m_requestTelemetryData.SetRequestFailure(RequestFailure_FileOpenInSession);

                m_putFileInfo.m_name.clear(); // this prevents this session from deleting the putfile while another session is using it
                throw ERROR_EXCEPTION << "(sid: " << m_sessionId << ") rename file "
                                      << (*oldNameTagValue).second << " currently opened by session "
                                      << sessionId << " can not be renamed at this time";
            }
            bool compress = compressFile((*newNameTagValue).second);
            if (compress) {
                (*newNameTagValue).second += ".gz";
                std::string::size_type idx = (*newNameTagValue).second.find("tmp_");
                if (std::string::npos != idx) {
                    (*newNameTagValue).second.erase(idx, 4);
                }
            }

            if (m_requestInfo.m_params.end() != finalPathsTagValue) {
                if ((*finalPathsTagValue).second.empty()) {
                    m_requestTelemetryData.SetRequestFailure(RequestFailure_MissingPathsTag);
                    throw ERROR_EXCEPTION << "missing values for paths tag";
                }

                // taking over final rename so need to remove tmp_ prefix if it exists
                // note if inline compression on, that will already have removed the tmp_
                // so only need to check if not inline compress
                if (!compress) {
                    std::string::size_type idx = (*newNameTagValue).second.find("tmp_");
                    if (std::string::npos != idx) {
                        (*newNameTagValue).second.erase(idx, 4);
                    }
                }

                // need to prepend completed_ediff and append time if a diff file
                std::string::size_type idx = (*newNameTagValue).second.find("completed_diff_");
                if (std::string::npos != idx) {
                    boost::filesystem::path tmpNewPath((*newNameTagValue).second);
                    std::string tmpNewName(tmpNewPath.filename().string());
                    tmpNewName.insert(0, "completed_ediff");
                    std::time_t mtime = last_write_time(extOldName);
                    idx = tmpNewName.find(".dat");
                    if (std::string::npos == idx) {
                        // todo: is this good enough .dat should always be there for this file
                        idx = tmpNewName.size();
                    }
                    tmpNewName.insert(idx, "_");
                    ++idx;
                    tmpNewName.insert(idx, boost::lexical_cast<std::string>(mtime));
                    if (tmpNewPath.has_parent_path()) {
                        tmpNewPath.remove_filename();
                        tmpNewPath /= tmpNewName;
                    } else {
                        tmpNewPath = tmpNewName;
                    }
                    (*newNameTagValue).second = tmpNewPath.string();
                    shouldAppendMTimeInUtc = false; // since already appended
                }
            }

            if (shouldAppendMTimeInUtc) {
                std::time_t mtime = last_write_time(extOldName);
                boost::filesystem::path tmpNewPath(newNameTagValue->second);
                std::string tmpNewName(tmpNewPath.stem().string());

                tmpNewName += '_';
                tmpNewName += boost::lexical_cast<std::string>(mtime);
                tmpNewName += tmpNewPath.extension().string();

                if (tmpNewPath.has_parent_path()) {
                    tmpNewPath.remove_filename();
                    tmpNewPath /= tmpNewName;
                }
                else {
                    tmpNewPath = tmpNewName;
                }

                newNameTagValue->second = tmpNewPath.string();
            }

            boost::filesystem::path newFullNamePath;
            // do not perform allowed_dir check in case finalPathsTagValue is set; will be performed later
            getFullPathName((*newNameTagValue).second, newFullNamePath, m_requestInfo.m_params.end() == finalPathsTagValue);
            extendedLengthPath_t extNewName(ExtendedLengthPath::name(newFullNamePath.string()));
            
            if (m_requestInfo.m_params.end() == finalPathsTagValue) {
                // boost rename is too restrictive, so for case were rename
                // should be allowed, need to delete new name if it exists
                if (boost::filesystem::exists(extNewName)
                    && boost::filesystem::is_regular_file(extNewName)) {
                    boost::filesystem::remove(extNewName);
                }
                boost::filesystem::rename(extOldName, extNewName);
            } else {
                RenameFinal::rename(extOldName,
                                    extNewName,
                                    m_putFileInfo.m_createDirs || m_serverOptions->createPaths(),
                                    (*finalPathsTagValue).second,
                                    m_serverOptions->copyOnRenameLinkFailure(),
                                    MAKE_GET_FULL_PATH_CALLBACK_MEM_FUN(&RequestHandler::getFullPathNameWrapper, this),
                                    MAKE_CLOSE_FILE_CALLBACK_MEM_FUN(&RequestHandler::closeFileCallback, this));
                // FIXME: if clustered, need to update the other cluster nodes too
                updateRpoMonitor(extOldName);
            }

            if (GetCSMode() == CS_MODE_RCM)
            {
                std::string fileName = extNewName.filename().string();
                // Only updating the monitor.txt file in case of diff, tso and tag files
                if (fileName.find("_diff_") != std::string::npos ||
                    fileName.find("_tso_") != std::string::npos ||
                    fileName.find("_tag_") != std::string::npos)
                {
                    updateRpoMonitor(extNewName);
                }
            }

            sendSuccess();
            logRequestDone();
        }
    } catch (std::exception const & e) {
        m_requestTelemetryData.SetRequestFailure(RequestFailure_RenameFileFailed);
        throw ERROR_EXCEPTION << (*oldNameTagValue).second <<" to " << (*newNameTagValue).second << " failed: " << e.what();
    }

    m_requestTelemetryData.CompletingOp();

    sessionLogoutGuard.dismiss();
    m_requestInfo.m_completedCallback();
}