void XmlFileWriter::write(const char *pcszFilename, bool fSafe) { if (!fSafe) writeInternal(pcszFilename, fSafe); else { /* Empty string and directory spec must be avoid. */ if (RTPathFilename(pcszFilename) == NULL) throw xml::LogicError(RT_SRC_POS); /* Construct both filenames first to ease error handling. */ char szTmpFilename[RTPATH_MAX]; int rc = RTStrCopy(szTmpFilename, sizeof(szTmpFilename) - strlen(s_pszTmpSuff), pcszFilename); if (RT_FAILURE(rc)) throw EIPRTFailure(rc, "RTStrCopy"); strcat(szTmpFilename, s_pszTmpSuff); char szPrevFilename[RTPATH_MAX]; rc = RTStrCopy(szPrevFilename, sizeof(szPrevFilename) - strlen(s_pszPrevSuff), pcszFilename); if (RT_FAILURE(rc)) throw EIPRTFailure(rc, "RTStrCopy"); strcat(szPrevFilename, s_pszPrevSuff); /* Write the XML document to the temporary file. */ writeInternal(szTmpFilename, fSafe); /* Make a backup of any existing file (ignore failure). */ uint64_t cbPrevFile; rc = RTFileQuerySize(pcszFilename, &cbPrevFile); if (RT_SUCCESS(rc) && cbPrevFile >= 16) RTFileRename(pcszFilename, szPrevFilename, RTPATHRENAME_FLAGS_REPLACE); /* Commit the temporary file. Just leave the tmp file behind on failure. */ rc = RTFileRename(szTmpFilename, pcszFilename, RTPATHRENAME_FLAGS_REPLACE); if (RT_FAILURE(rc)) throw EIPRTFailure(rc, "Failed to replace '%s' with '%s'", pcszFilename, szTmpFilename); /* Flush the directory changes (required on linux at least). */ RTPathStripFilename(szTmpFilename); rc = RTDirFlush(szTmpFilename); AssertMsg(RT_SUCCESS(rc) || rc == VERR_NOT_SUPPORTED || rc == VERR_NOT_IMPLEMENTED, ("%Rrc\n", rc)); } }
int main(int argc, char **argv) { RTR3InitExe(argc, &argv, 0); /* * Arguments or any -? or --help? */ if (argc <= 1 || HasHelpOption(argc, argv)) { RTPrintf("usage: tstMove [-efdr] <src> <dst>\n" "\n" " -f File only.\n" " -d Directory only.\n" " -m Use move operation instead of rename. (implies -f)\n" " -r Replace existing destination.\n" ); return 1; } /* * Parse args. */ const char *pszNew = NULL; const char *pszOld = NULL; bool fDir = false; bool fFile = false; bool fReplace = false; bool fMoveFile = false; for (int argi = 1; argi < argc; argi++) { if (argv[argi][0] == '-') { const char *psz = &argv[argi][1]; do { switch (*psz) { case 'd': fDir = true; fMoveFile = false; break; case 'f': fFile = true; break; case 'm': fMoveFile = true; fDir = false; fFile = true; break; case 'r': fReplace = true; break; default: RTPrintf("tstRTFileMove: syntax error: Unknown option '%c' in '%s'!\n", *psz, argv[argi]); return 1; } } while (*++psz); } else if (!pszOld) pszOld = argv[argi]; else if (!pszNew) pszNew = argv[argi]; else { RTPrintf("tstRTFileMove: syntax error: too many filenames!\n"); return 1; } } if (!pszNew || !pszOld) { RTPrintf("tstRTFileMove: syntax error: too few filenames!\n"); return 1; } /* * Do the operation. */ int rc; if (!fDir && !fFile) rc = RTPathRename(pszOld, pszNew, fReplace ? RTPATHRENAME_FLAGS_REPLACE : 0); else if (fDir) rc = RTDirRename( pszOld, pszNew, fReplace ? RTPATHRENAME_FLAGS_REPLACE : 0); else if (!fMoveFile) rc = RTFileRename(pszOld, pszNew, fReplace ? RTPATHRENAME_FLAGS_REPLACE : 0); else rc = RTFileMove( pszOld, pszNew, fReplace ? RTFILEMOVE_FLAGS_REPLACE : 0); RTPrintf("The API returned %Rrc\n", rc); return !RT_SUCCESS(rc); }
RTDECL(int) RTFileMove(const char *pszSrc, const char *pszDst, unsigned fMove) { /* * Validate input. */ AssertMsgReturn(VALID_PTR(pszSrc), ("%p\n", pszSrc), VERR_INVALID_POINTER); AssertMsgReturn(VALID_PTR(pszDst), ("%p\n", pszDst), VERR_INVALID_POINTER); AssertMsgReturn(*pszSrc, ("%p\n", pszSrc), VERR_INVALID_PARAMETER); AssertMsgReturn(*pszDst, ("%p\n", pszDst), VERR_INVALID_PARAMETER); AssertMsgReturn(!(fMove & ~RTFILEMOVE_FLAGS_REPLACE), ("%#x\n", fMove), VERR_INVALID_PARAMETER); /* * Try RTFileRename first. */ Assert(RTPATHRENAME_FLAGS_REPLACE == RTFILEMOVE_FLAGS_REPLACE); unsigned fRename = fMove; int rc = RTFileRename(pszSrc, pszDst, fRename); if (rc == VERR_NOT_SAME_DEVICE) { const char *pszDelete = NULL; /* * The source and target are not on the same device, darn. * We'll try open both ends and perform a copy. */ RTFILE FileSrc; rc = RTFileOpen(&FileSrc, pszSrc, RTFILE_O_READ | RTFILE_O_DENY_WRITE | RTFILE_O_OPEN); if (RT_SUCCESS(rc)) { RTFILE FileDst; rc = RTFileOpen(&FileDst, pszDst, RTFILE_O_WRITE | RTFILE_O_DENY_ALL | RTFILE_O_CREATE_REPLACE); if (RT_SUCCESS(rc)) { rc = RTFileCopyByHandles(FileSrc, FileDst); if (RT_SUCCESS(rc)) pszDelete = pszSrc; else { pszDelete = pszDst; Log(("RTFileMove('%s', '%s', %#x): copy failed, rc=%Rrc\n", pszSrc, pszDst, fMove, rc)); } /* try delete without closing, and could perhaps avoid some trouble */ int rc2 = RTFileDelete(pszDelete); if (RT_SUCCESS(rc2)) pszDelete = NULL; RTFileClose(FileDst); } else Log(("RTFileMove('%s', '%s', %#x): failed to create destination, rc=%Rrc\n", pszSrc, pszDst, fMove, rc)); RTFileClose(FileSrc); } else Log(("RTFileMove('%s', '%s', %#x): failed to open source, rc=%Rrc\n", pszSrc, pszDst, fMove, rc)); /* if we failed to close it while open, close it now */ if (pszDelete) { int rc2 = RTFileDelete(pszDelete); if (RT_FAILURE(rc2)) Log(("RTFileMove('%s', '%s', %#x): failed to delete '%s', rc2=%Rrc (rc=%Rrc)\n", pszSrc, pszDst, fMove, pszDelete, rc2, rc)); } } LogFlow(("RTDirRename(%p:{%s}, %p:{%s}, %#x): returns %Rrc\n", pszSrc, pszSrc, pszDst, pszDst, fMove, rc)); return rc; }