patchmain.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296
  1. /*##############################################################################
  2. HPCC SYSTEMS software Copyright (C) 2012 HPCC Systems®.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. ############################################################################## */
  13. #include <stdio.h>
  14. #include "jlog.hpp"
  15. #include "keydiff.hpp"
  16. #include "mpcomm.hpp"
  17. void usage(bool isHelp)
  18. {
  19. printf("usage:\n"
  20. " keypatch [options] patch oldindex newindex\n"
  21. " keypatch [options] patch\n"
  22. "options are:\n"
  23. " -o --overwrite overwrite new index file if it exists\n"
  24. " -n --nooverwrite abort if new index file exists (default)\n"
  25. " -t --transmit port ip:port send TLK data to a receiver to be collated\n"
  26. " (sends from given port to given ip:port)\n"
  27. " -s --skiptlk suppresses the warning when patch contains\n"
  28. " TLK header data and -r is not selected\n"
  29. " -p --progress freq log progress reading old index at intervals of freq bytes\n"
  30. "Using the single argument form of the command, the filenames of the old\n"
  31. "and new index files are those used to generate the patch.\n"
  32. "\n"
  33. "usage:\n"
  34. " keypatch [options] [-r | --receive] port num patch oldindex newindex newtlk\n"
  35. " keypatch [options] [-r | --receive] port num patch\n"
  36. "options are:\n"
  37. " -o --overwrite overwrite new index and TLK files if they exist\n"
  38. " -n --nooverwrite abort if new index or TLK files exist (default)\n"
  39. "These forms of the command listen on the given port to receive and collate TLK\n"
  40. "data (in addition to applying patch for this part as normal). They will listen\n"
  41. "for num parts.\n"
  42. "\n"
  43. "usage:\n"
  44. " keypatch [-v | --version ]\n"
  45. " keypatch [-h | -? | --help ]\n"
  46. " keypatch [-i| --info] patch\n"
  47. "The --info option shows the names of the old and new index files\n"
  48. "and the version of keydiff used to generate the patch, then stops.\n\n");
  49. releaseAtoms();
  50. exit(isHelp ? 0 : 2);
  51. }
  52. class KeyPatchProgressCallback : public CInterface, public IKeyDiffProgressCallback
  53. {
  54. public:
  55. IMPLEMENT_IINTERFACE;
  56. virtual void handle(offset_t bytesRead) { PROGLOG("Read %" I64F "d bytes from old index", bytesRead); }
  57. };
  58. void version(bool isHelp)
  59. {
  60. StringBuffer buff("This is keypatch version ");
  61. getKeyDiffVersion(buff).append(".\nIt can apply patches generated by keydiff since version ");
  62. getKeyDiffMinDiffVersionForPatch(buff).append(".\n");
  63. buff.append("To discover whether it can apply patches generated by versions\n"
  64. "of keydiff later than itself, see keydiff -v.\n\n");
  65. printf("%s", buff.str());
  66. if(isHelp)
  67. usage(true);
  68. releaseAtoms();
  69. exit(0);
  70. }
  71. typedef enum
  72. {
  73. KEYPATCH_implicit,
  74. KEYPATCH_explicit,
  75. KEYPATCH_info
  76. } KeyPatchMode;
  77. class KeyPatchParams
  78. {
  79. public:
  80. KeyPatchParams() : overwrite(false), mode(KEYPATCH_implicit), xmitTLK(false), recvTLK(false), ignoreTLK(false), progressFrequency(0) {}
  81. StringBuffer patch;
  82. StringBuffer oldIndex;
  83. StringBuffer newIndex;
  84. StringBuffer newTLK;
  85. bool overwrite;
  86. KeyPatchMode mode;
  87. bool xmitTLK;
  88. bool recvTLK;
  89. SocketEndpoint xmitEp;
  90. unsigned recvNum;
  91. unsigned tlkPort;
  92. bool ignoreTLK;
  93. offset_t progressFrequency;
  94. };
  95. void getParams(unsigned argc, char * const * argv, KeyPatchParams & params)
  96. {
  97. unsigned arg = 1;
  98. while((arg<argc) && (*argv[arg] == '-'))
  99. {
  100. if((strcmp(argv[arg], "-o") == 0) || (strcmp(argv[arg], "--overwrite") == 0))
  101. params.overwrite = true;
  102. else if((strcmp(argv[arg], "-n") == 0) || (strcmp(argv[arg], "--nooverwrite") == 0))
  103. params.overwrite = false;
  104. else if((strcmp(argv[arg], "-i") == 0) || (strcmp(argv[arg], "--info") == 0))
  105. params.mode = KEYPATCH_info;
  106. else if((strcmp(argv[arg], "-t") == 0) || (strcmp(argv[arg], "--transmit") == 0))
  107. {
  108. if((argc-arg)<=2) usage(false);
  109. params.xmitTLK = true;
  110. params.tlkPort = atoi(argv[++arg]);
  111. params.xmitEp.set(argv[++arg]);
  112. if(params.tlkPort == 0)
  113. throw MakeStringException(0, "Bad local port on TLK transmit");
  114. if(params.xmitEp.port == 0)
  115. throw MakeStringException(0, "Bad remote ip:port on TLK transmit");
  116. }
  117. else if((strcmp(argv[arg], "-r") == 0) || (strcmp(argv[arg], "--receive") == 0))
  118. {
  119. if((argc-arg)<=2) usage(false);
  120. params.recvTLK = true;
  121. params.tlkPort = atoi(argv[++arg]);
  122. params.recvNum = atoi(argv[++arg]);
  123. if(params.tlkPort == 0)
  124. throw MakeStringException(0, "Bad local port on TLK receive");
  125. if(params.recvNum == 0)
  126. throw MakeStringException(0, "Bad number of parts on TLK receive");
  127. }
  128. else if((strcmp(argv[arg], "-s") == 0) || (stricmp(argv[arg], "--skiptlk") == 0))
  129. params.ignoreTLK = true;
  130. else if((strcmp(argv[arg], "-p") == 0) || (strcmp(argv[arg], "--progress") == 0))
  131. {
  132. if((argc-arg)<=1) usage(false);
  133. ++arg;
  134. offset_t freq = atoi64_l(argv[arg], strlen(argv[arg]));
  135. if(freq <= 0) usage(false);
  136. params.progressFrequency = freq;
  137. }
  138. else if((strcmp(argv[arg], "-v") == 0) || (strcmp(argv[arg], "--version") == 0))
  139. version(false);
  140. else if((strcmp(argv[arg], "-h") == 0) || (strcmp(argv[arg], "-?") == 0) || (strcmp(argv[arg], "--help") == 0))
  141. version(true);
  142. else
  143. usage(false);
  144. arg++;
  145. }
  146. if((params.mode == KEYPATCH_info) && (params.xmitTLK || params.recvTLK))
  147. throw MakeStringException(0, "Cannot specify info option with TLK transmit or receive");
  148. if(params.xmitTLK && params.recvTLK)
  149. throw MakeStringException(0, "Cannot specify both TLK transmit and receive");
  150. unsigned argsRqd = (params.recvTLK ? 4 : 3);
  151. if((argc == arg+argsRqd) && (params.mode == KEYPATCH_implicit))
  152. {
  153. params.patch.append(argv[arg++]);
  154. params.oldIndex.append(argv[arg++]);
  155. params.newIndex.append(argv[arg++]);
  156. if(params.recvTLK)
  157. params.newTLK.append(argv[arg++]);
  158. params.mode = KEYPATCH_explicit;
  159. }
  160. else if(argc == arg+1)
  161. {
  162. params.patch.append(argv[arg++]);
  163. }
  164. else
  165. {
  166. usage(false);
  167. }
  168. }
  169. void showInfo(char const * patch, IKeyDiffApplicator * applicator)
  170. {
  171. unsigned short headerVersionMajor, headerVersionMinor, headerMinPatchVersionMajor, headerMinPatchVersionMinor;
  172. applicator->getHeaderVersionInfo(headerVersionMajor, headerVersionMinor, headerMinPatchVersionMajor, headerMinPatchVersionMinor);
  173. printf("Header info for patch %s:\n"
  174. "Version of keydiff: %u.%u\n"
  175. "Min version of keypatch required: %u.%u\n", patch, headerVersionMajor, headerVersionMinor, headerMinPatchVersionMajor, headerMinPatchVersionMinor);
  176. StringBuffer versionError;
  177. if(applicator->compatibleVersions(versionError))
  178. {
  179. StringAttr oldindex, newindex, newTLK;
  180. bool tlkInfo;
  181. applicator->getHeaderFileInfo(oldindex, newindex, tlkInfo, newTLK);
  182. printf("Old index filename: %s\n"
  183. "New index filename: %s\n\n", oldindex.get(), newindex.get());
  184. if(tlkInfo)
  185. printf("Header includes info for new top level key, filename: %s\n\n", newTLK.get());
  186. }
  187. else
  188. {
  189. printf("\nCannot use patch: %s\n\n", versionError.str());
  190. }
  191. }
  192. class CNodeSender : public CInterface, public INodeSender
  193. {
  194. public:
  195. IMPLEMENT_IINTERFACE;
  196. CNodeSender(unsigned _port, SocketEndpoint const & ep) : port(_port), dest(createINode(ep)) {}
  197. virtual void send(CNodeInfo & info)
  198. {
  199. CMessageBuffer mb;
  200. info.serialize(mb);
  201. startMPServer(port);
  202. PROGLOG("Sending tlk");
  203. queryWorldCommunicator().send(mb, dest, MPTAG_KEYDIFF);
  204. stopMPServer();
  205. }
  206. private:
  207. unsigned port;
  208. Owned<INode> dest;
  209. };
  210. class CNodeReceiver : public CInterface, public INodeReceiver
  211. {
  212. public:
  213. IMPLEMENT_IINTERFACE;
  214. CNodeReceiver(unsigned port)
  215. {
  216. startMPServer(port);
  217. }
  218. ~CNodeReceiver()
  219. {
  220. stopMPServer();
  221. }
  222. virtual bool recv(CNodeInfo & info)
  223. {
  224. if(queryWorldCommunicator().recv(mb, 0, MPTAG_KEYDIFF))
  225. {
  226. info.deserialize(mb);
  227. return true;
  228. }
  229. return false;
  230. }
  231. virtual void stop()
  232. {
  233. queryWorldCommunicator().cancel(0, MPTAG_KEYDIFF);
  234. }
  235. private:
  236. CMessageBuffer mb;
  237. };
  238. int main(int argc, char * const * argv)
  239. {
  240. InitModuleObjects();
  241. try
  242. {
  243. KeyPatchParams params;
  244. getParams(argc, argv, params);
  245. Owned<IKeyDiffApplicator> applicator;
  246. if(params.mode == KEYPATCH_explicit)
  247. applicator.setown(createKeyDiffApplicator(params.patch.str(), params.oldIndex.str(), params.newIndex.str(), params.newTLK.str(), params.overwrite, params.ignoreTLK));
  248. else
  249. applicator.setown(createKeyDiffApplicator(params.patch.str(), params.overwrite, params.ignoreTLK));
  250. if(params.mode == KEYPATCH_info)
  251. showInfo(params.patch.str(), applicator);
  252. else
  253. {
  254. if(params.xmitTLK)
  255. applicator->setTransmitTLK(new CNodeSender(params.tlkPort, params.xmitEp));
  256. else if(params.recvTLK)
  257. applicator->setReceiveTLK(new CNodeReceiver(params.tlkPort), params.recvNum);
  258. if(params.progressFrequency)
  259. applicator->setProgressCallback(new KeyPatchProgressCallback, params.progressFrequency);
  260. applicator->run();
  261. }
  262. }
  263. catch(IException * e)
  264. {
  265. EXCLOG(e);
  266. e->Release();
  267. releaseAtoms();
  268. return 1;
  269. }
  270. releaseAtoms();
  271. return 0;
  272. }