From: Petr Tesarik <ptesarik@suse.cz>
Date: Tue, 14 Apr 2015 23:14:56 +0200
Subject: Implement SFTPTransfer::mkpath and call it at initialization
References: FATE#318874, bsc#917747
Patch-mainline: v0.8.16
Git-commit: 3d32bb0bb6e2e5954066214f48d82cbcbf7d890c

Similar to other transfer methods, the target directory is created in
the constructor.

Signed-off-by: Petr Tesarik <ptesarik@suse.cz>
---
 kdumptool/sshtransfer.cc |   69 +++++++++++++++++++++++++++++++++++++++++++++++
 kdumptool/sshtransfer.h  |   12 ++++++++
 2 files changed, 81 insertions(+)

--- a/kdumptool/sshtransfer.cc
+++ b/kdumptool/sshtransfer.cc
@@ -274,6 +274,8 @@ SFTPTransfer::SFTPTransfer(const RootDir
 		     Stringutil::number2string(unsigned(type)));
     m_proto_ver = initpkt.getInt32();
     Debug::debug()->dbg("Remote SFTP version %lu", m_proto_ver);
+
+    mkpath(FileUtil::pathconcat(parser.getPath(), getSubDir()));
 }
 
 /* -------------------------------------------------------------------------- */
@@ -305,6 +307,73 @@ void SFTPTransfer::perform(DataProvider
 }
 
 /* -------------------------------------------------------------------------- */
+bool SFTPTransfer::exists(const string &file)
+{
+    Debug::debug()->trace("SFTPTransfer::exists(%s)", file.c_str());
+
+    SFTPPacket pkt;
+    pkt.addByte(SSH_FXP_STAT);
+    pkt.addInt32(nextId());
+    pkt.addString(file);
+    sendPacket(pkt);
+
+    recvPacket(pkt);
+    unsigned char type = pkt.getByte();
+    unsigned long id = pkt.getInt32();
+    if (id != m_lastid)
+	throw KError("SFTP request/reply id mismatch");
+
+    if (type == SSH_FXP_ATTRS)
+	return true;
+
+    if (type != SSH_FXP_STATUS)
+	throw KError("Invalid response to SSH_FXP_LSTAT: type " +
+		     Stringutil::number2string(unsigned(type)));
+
+    unsigned long errcode = pkt.getInt32();
+    if (errcode != SSH_FX_NO_SUCH_FILE)
+	throw KSFTPError("stat failed on " + file, errcode);
+
+    return false;
+}
+
+/* -------------------------------------------------------------------------- */
+void SFTPTransfer::mkpath(const std::string &path)
+{
+    Debug::debug()->trace("SFTPTransfer::mkpath(%s)", path.c_str());
+
+    if (!exists(path)) {
+	string dir = Stringutil::rtrim(path, PATH_SEPARATOR);
+	string::size_type pos = dir.rfind(PATH_SEPARATOR);
+	if (pos > 0 && pos != string::npos) {
+	    dir.erase(pos);
+	    mkpath(dir);
+	}
+
+	SFTPPacket pkt;
+	pkt.addByte(SSH_FXP_MKDIR);
+	pkt.addInt32(nextId());
+	pkt.addString(path);
+	pkt.addInt32(0UL);
+	sendPacket(pkt);
+
+	recvPacket(pkt);
+	unsigned char type = pkt.getByte();
+	unsigned long id = pkt.getInt32();
+	if (id != m_lastid)
+	    throw KError("SFTP request/reply id mismatch");
+
+	if (type != SSH_FXP_STATUS)
+	    throw KError("Invalid response to SSH_FXP_MKDIR: type " +
+			 Stringutil::number2string(unsigned(type)));
+
+	unsigned long errcode = pkt.getInt32();
+	if (errcode != SSH_FX_OK)
+	    throw KSFTPError("mkdir failed on " + path, errcode);
+    }
+}
+
+/* -------------------------------------------------------------------------- */
 StringVector SFTPTransfer::makeArgs(void)
 {
     const RootDirURL &target = getURLVector().front();
--- a/kdumptool/sshtransfer.h
+++ b/kdumptool/sshtransfer.h
@@ -104,6 +104,10 @@ class KSFTPError : public KError {
 enum {
     SSH_FXP_INIT	=   1,
     SSH_FXP_VERSION	=   2,
+    SSH_FXP_MKDIR	=  14,
+    SSH_FXP_STAT	=  17,
+    SSH_FXP_STATUS	= 101,
+    SSH_FXP_ATTRS	= 105,
 };
 
 /**
@@ -189,13 +193,21 @@ class SFTPTransfer : public URLTransfer
     protected:
 	static const int MY_PROTO_VER = 3; // our advertised version
 
+        bool exists(const std::string &file);
+        void mkpath(const std::string &path);
+
     private:
 	SubProcess m_process;
 	int m_fdreq, m_fdresp;
 	unsigned long m_proto_ver; // remote SFTP protocol version
+	unsigned long m_lastid;
 
 	StringVector makeArgs(void);
 
+	unsigned long nextId(void)
+	throw ()
+	{ return m_lastid = (m_lastid + 1) & ((1UL << 32) - 1); }
+
 	void sendPacket(SFTPPacket &pkt);
 	void recvPacket(SFTPPacket &pkt);
 	void recvBuffer(unsigned char *bufp, size_t buflen);
