isrepair.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475
  1. /*
  2. * CDE - Common Desktop Environment
  3. *
  4. * Copyright (c) 1993-2012, The Open Group. All rights reserved.
  5. *
  6. * These libraries and programs are free software; you can
  7. * redistribute them and/or modify them under the terms of the GNU
  8. * Lesser General Public License as published by the Free Software
  9. * Foundation; either version 2 of the License, or (at your option)
  10. * any later version.
  11. *
  12. * These libraries and programs are distributed in the hope that
  13. * they will be useful, but WITHOUT ANY WARRANTY; without even the
  14. * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
  15. * PURPOSE. See the GNU Lesser General Public License for more
  16. * details.
  17. *
  18. * You should have received a copy of the GNU Lesser General Public
  19. * License along with these libraries and programs; if not, write
  20. * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
  21. * Floor, Boston, MA 02110-1301 USA
  22. */
  23. /*%% (c) Copyright 1993, 1994 Hewlett-Packard Company */
  24. /*%% (c) Copyright 1993, 1994 International Business Machines Corp. */
  25. /*%% (c) Copyright 1993, 1994 Sun Microsystems, Inc. */
  26. /*%% (c) Copyright 1993, 1994 Novell, Inc. */
  27. /*%% $TOG: isrepair.c /main/5 1998/04/10 08:04:42 mgreess $ */
  28. /* @(#)isrepair.c 1.7 93/07/30
  29. * Copyright (c) 1988, 1993 by Sun Microsystems, Inc.
  30. */
  31. /*
  32. * isrepair.c
  33. *
  34. * Description:
  35. * Repair an ISAM file.
  36. */
  37. #include "isam_impl.h"
  38. #include <unistd.h>
  39. #include <stdlib.h>
  40. #include <signal.h>
  41. #include <stdio.h>
  42. /*
  43. * err = isrepair(isfname, verbose)
  44. *
  45. * isrepair repairs an ISAM file.
  46. *
  47. * The algorithm used is as the following:
  48. * 1. Read the control page of the possibly damaged file. We assume
  49. * that the control page is not damaged.
  50. * 2. Open a new ISAM file with ~ suffix.
  51. * 3. Scan .rec file (and .var file if variable length records file)
  52. * retrieve all records not marked as deleted, and write them
  53. * to the ~ ISAM file.
  54. * 4. Delete the old ISAM file.
  55. * 5. Rename ~ file to the original file name.
  56. * 6. Build all indexes.
  57. *
  58. * verbose option (if set to nonzero) will print messages to stdout.
  59. */
  60. Static char *rp_readrecord_v(), *rp_readrecord_f();
  61. Static int printkey(int, struct keydesc *, int (*)(const char *, ...));
  62. Static void cmd_error(const char *, int (*)(const char *, ...));
  63. Static int typeletter();
  64. Static int rp_readcntlpg();
  65. static int isnoprintf(const char *, ...);
  66. int isrepair(char *isfname, int verbose)
  67. {
  68. extern char *rp_readrecord_v(), *rp_readrecord_f();
  69. char cntlpg[ISCNTLSIZE];
  70. int datfd = -1, indfd = -1, varfd = -1;
  71. int minreclen, maxreclen;
  72. int nrecords_fromcntl;
  73. int varflag;
  74. char nameBuf [MAXPATHLEN];
  75. char *namebuf;
  76. int isfd = -1;
  77. struct keydesc2 keydesc2;
  78. int i;
  79. long offset, recfile_end;
  80. char *prec;
  81. long recnum;
  82. int nrecords_found, diff;
  83. long lastrecno;
  84. struct keydesc keydesc;
  85. int (*print)(const char *, ...);
  86. sigset_t oldmask;
  87. sigset_t allsignals;
  88. char Buffer[BUFSIZ];
  89. char *buffer = NULL;
  90. print = verbose ? printf : isnoprintf;
  91. datfd = indfd = varfd = -1;
  92. /*
  93. * Open UNIX files.
  94. */
  95. if (strlen(isfname) + 10 >= MAXPATHLEN)
  96. namebuf = (char*) malloc(strlen(isfname) + 10);
  97. else
  98. namebuf = nameBuf;
  99. (void)strcpy(namebuf, isfname);
  100. _makedat_isfname(namebuf);
  101. datfd = open(namebuf, O_RDONLY);
  102. if (datfd > -1) {
  103. if(fcntl(datfd, F_SETFD, 1) == -1) {
  104. close(datfd);
  105. datfd = -1;
  106. }
  107. }
  108. (void)strcpy(namebuf, isfname);
  109. _makeind_isfname(namebuf);
  110. indfd = open(namebuf, O_RDONLY);
  111. if (indfd > -1) {
  112. if(fcntl(indfd, F_SETFD, 1) == -1) {
  113. close(indfd);
  114. indfd = -1;
  115. }
  116. }
  117. (void)strcpy(namebuf, isfname);
  118. _makevar_isfname(namebuf);
  119. varfd = open(namebuf, O_RDONLY);
  120. if (varfd > -1) {
  121. if(fcntl(varfd, F_SETFD, 1) == -1) {
  122. close(varfd);
  123. varfd = -1;
  124. }
  125. }
  126. (void)print("Reading control page from %s.rec file...\n",
  127. isfname);
  128. if (rp_readcntlpg(datfd, cntlpg) == ISERROR) {
  129. (void)print("Cannot read the control page\n");
  130. goto ERROR;
  131. }
  132. /*
  133. * Check magic. Repair only ISAM files!!!
  134. */
  135. if (strncmp(cntlpg + CP_MAGIC_OFF, ISMAGIC, strlen(ISMAGIC)) != 0) {
  136. (void)print("Bad magic in %s.rec\n", isfname);
  137. goto ERROR;
  138. }
  139. varflag = ldint(cntlpg + CP_VARFLAG_OFF);
  140. minreclen = ldint(cntlpg + CP_MINRECLEN_OFF);
  141. maxreclen = ldint(cntlpg + CP_MAXRECLEN_OFF);
  142. /*
  143. * Check for maxreclen field value of -1. This could have occurred due to
  144. * ISMAXRECLEN being incorrectly set to 65535 in an earlier version. If
  145. * this field is -1 and it's a variable length record, reset to the new
  146. * value of MAXRECLEN. This means that this field will be repaired when
  147. * the control block is written back to disk.
  148. */
  149. if (maxreclen == -1 && varflag) {
  150. maxreclen = ISMAXRECLEN;
  151. }
  152. lastrecno = ldlong(cntlpg + CP_LASTRECNO_OFF);
  153. nrecords_fromcntl = ldlong(cntlpg + CP_NRECORDS_OFF);
  154. /*
  155. * Open output file. Use ~ as suffix.
  156. */
  157. (void)sprintf(namebuf, "%s~", isfname);
  158. (void)print("Opening temporary ISAM file '%s'...\n",
  159. namebuf);
  160. isreclen = minreclen;
  161. if ((isfd = isbuild(namebuf, maxreclen, nokey, ISINOUT + ISEXCLLOCK +
  162. (varflag?ISVARLEN:0))) == ISERROR) {
  163. (void)print("Cannot open temporary ISAM file %s\n",
  164. namebuf);
  165. if (iserrno == EEXIST)
  166. (void)print("File %s already exists\n", namebuf);
  167. goto ERROR;
  168. }
  169. /*
  170. * Scan .rec file and read all undeleted records.
  171. */
  172. (void)print("Salvaging records from %s.rec%s file...\n",
  173. isfname, varflag?" (and .var file)" : "");
  174. offset = ISCNTLSIZE;
  175. recfile_end = lseek(datfd, 0L, 2);
  176. recnum = 1;
  177. nrecords_found = 0;
  178. while (recnum <= lastrecno && offset < recfile_end - minreclen) {
  179. if (varflag) {
  180. prec = rp_readrecord_v(datfd, varfd, offset, minreclen, maxreclen);
  181. offset += minreclen + LONGSIZE;
  182. }
  183. else {
  184. prec = rp_readrecord_f(datfd, offset, minreclen);
  185. offset += minreclen + 1;
  186. }
  187. if (prec != NULL) {
  188. if (iswrrec(isfd, recnum, prec) == ISERROR) {
  189. cmd_error("iswrrec", print);
  190. goto ERROR;
  191. }
  192. nrecords_found++;
  193. }
  194. recnum++;
  195. }
  196. diff = nrecords_found - nrecords_fromcntl;
  197. if (diff == 0)
  198. (void)print("All records found - total %d records\n",
  199. nrecords_found);
  200. else
  201. (void)print("%d records found - %d records %s than in header\n",
  202. nrecords_found, diff, diff > 0 ?
  203. "more" : "less");
  204. /*
  205. * Close all file descriptors.
  206. */
  207. if(datfd != -1) {
  208. close(datfd);
  209. datfd = -1;
  210. }
  211. if(indfd != -1) {
  212. close(indfd);
  213. indfd = -1;
  214. }
  215. if(varfd != -1) {
  216. close(varfd);
  217. varfd = -1;
  218. }
  219. (void)isclose(isfd);
  220. (void) sigfillset(&allsignals);
  221. (void) sigprocmask(SIG_SETMASK, &allsignals, &oldmask);
  222. (void)print("Erasing ISAM file '%s'...\n", isfname);
  223. /* if (iserase(isfname) != ISOK) {
  224. cmd_error("iserase", print);
  225. goto ERROR;
  226. }
  227. */
  228. if (strlen(isfname) + 5 >= MAXPATHLEN)
  229. buffer = (char*) malloc(strlen(isfname) + 5);
  230. else
  231. buffer = Buffer;
  232. (void)sprintf(buffer,"%s.rec", isfname);
  233. (void)unlink(buffer);
  234. (void)sprintf(buffer,"%s.ind", isfname);
  235. (void)unlink(buffer);
  236. (void)sprintf(buffer,"%s.var", isfname);
  237. (void)unlink(buffer);
  238. (void)sprintf(namebuf, "%s~", isfname);
  239. (void)print("Renaming ISAM file '%s' to '%s'...\n",
  240. namebuf, isfname);
  241. if (isrename(namebuf, isfname) != ISOK) {
  242. cmd_error("isrename", print);
  243. goto ERROR;
  244. }
  245. /*
  246. * Re-open the file and add keys.
  247. */
  248. if (ldshort(cntlpg + CP_NKEYS_OFF) > 0) {
  249. (void)print("Adding keys...\n");
  250. if ((isfd = isopen(isfname, ISEXCLLOCK + ISINOUT +
  251. (varflag?ISVARLEN:0))) == ISERROR) {
  252. cmd_error("isopen", print);
  253. goto ERROR;
  254. }
  255. for (i = 0; i < ldshort(cntlpg + CP_NKEYS_OFF); i++) {
  256. ldkey(&keydesc2, cntlpg + CP_KEYS_OFF + i * K2_LEN);
  257. _iskey_itox(&keydesc2, &keydesc);
  258. if (keydesc.k_nparts == 0) /* special case for no primary */
  259. continue;
  260. printkey (i+1, &keydesc, print);
  261. if (i == 0) {
  262. if (isaddprimary(isfd, &keydesc) == ISERROR) {
  263. cmd_error("isaddprimary", print);
  264. (void)isclose(isfd);
  265. goto ERROR;
  266. }
  267. }
  268. else {
  269. if (isaddindex(isfd, &keydesc) == ISERROR) {
  270. cmd_error("isaddindex", print);
  271. (void)isclose(isfd);
  272. goto ERROR;
  273. }
  274. }
  275. }
  276. }
  277. (void)isclose(isfd);
  278. (void)sigprocmask(SIG_SETMASK, &oldmask, NULL);
  279. print("...File repaired\n");
  280. if (buffer != Buffer) free(buffer);
  281. return (ISOK);
  282. ERROR:
  283. (void)print("\007Didn't repair ISAM file '%s'\n", isfname);
  284. if(datfd != -1) {
  285. close(datfd);
  286. }
  287. if(indfd != -1) {
  288. close(indfd);
  289. }
  290. if(varfd != -1) {
  291. close(varfd);
  292. }
  293. (void)isclose(isfd);
  294. if (namebuf != nameBuf) free(namebuf);
  295. if (buffer != Buffer) free(buffer);
  296. return (ISERROR);
  297. }
  298. /******* low level data access used by the 'repair' utility ******************/
  299. static char recordbuffer[ISMAXRECLEN + LONGSIZE];
  300. /* rp_readcntlpg() - Read the control page */
  301. Static int
  302. rp_readcntlpg(int datfd, char *cntlpg)
  303. {
  304. if (read (datfd, cntlpg, ISCNTLSIZE) != ISCNTLSIZE)
  305. return (ISERROR);
  306. return (ISOK);
  307. }
  308. /* rp_readrecord_f() - Read a record from .rec file */
  309. Static char *
  310. rp_readrecord_f(int datfd, long offset, int reclen)
  311. {
  312. if (lseek(datfd, offset, 0) != offset)
  313. return ((char *) NULL);
  314. if (read(datfd, recordbuffer, reclen + 1) != (reclen + 1))
  315. return ((char *) NULL);
  316. if (recordbuffer[0] == FL_RECDELETED)
  317. return ((char *) NULL);
  318. return (recordbuffer + 1);
  319. }
  320. /* rp_readrecord_v() - Read a record from .rec file */
  321. Static char *
  322. rp_readrecord_v(int datfd, int varfd, long offset, int minreclen, int maxreclen)
  323. {
  324. long tailoff;
  325. char frameheadbuf [2 * SHORTSIZE];
  326. int taillen;
  327. if (lseek(datfd, offset, 0) != offset)
  328. return ((char *) NULL);
  329. if (read(datfd, recordbuffer, minreclen + LONGSIZE) != (minreclen + LONGSIZE))
  330. return ((char *) NULL);
  331. if ((tailoff = ldlong(recordbuffer)) == VL_RECDELETED)
  332. return ((char *) NULL);
  333. isreclen = minreclen;
  334. /* Recover tail of the record */
  335. if (tailoff != VL_RECNOTAIL) {
  336. if (lseek(varfd, tailoff, 0) != tailoff)
  337. goto OKEXIT;
  338. if (read(varfd, frameheadbuf, 2 * SHORTSIZE) != 2 * SHORTSIZE)
  339. goto OKEXIT;
  340. taillen = (int) ldshort(frameheadbuf + VR_TAILLEN_OFF);
  341. if (taillen <= 0 || taillen + minreclen > maxreclen)
  342. goto OKEXIT;
  343. if (read(varfd, recordbuffer + LONGSIZE + isreclen, taillen) != taillen)
  344. goto OKEXIT;
  345. isreclen += taillen;
  346. }
  347. OKEXIT:
  348. return (recordbuffer + LONGSIZE);
  349. }
  350. static int
  351. isnoprintf(const char *s, ...)
  352. {
  353. return(0);
  354. }
  355. static int
  356. printkey(int n, struct keydesc *pkdesc, int (*print)(const char *, ...))
  357. {
  358. int i;
  359. struct keypart *pk;
  360. if (pkdesc->k_nparts == 0) {
  361. print("%3d: --- NO PRIMARY KEY ---\n", n);
  362. return 0;
  363. }
  364. if (n == 1)
  365. print("P%3d: %s ", n, (pkdesc->k_flags&ISDUPS) ?
  366. "DUPS " : "NODUPS");
  367. else
  368. print(" %3d: %s ", n, (pkdesc->k_flags&ISDUPS) ?
  369. "DUPS " : "NODUPS");
  370. for (i = 0; i < pkdesc->k_nparts; i++) {
  371. pk = pkdesc->k_part + i;
  372. print(" %d%c%d%s", pk->kp_start,
  373. typeletter(pk->kp_type & ~ISDESC), pk->kp_leng,
  374. (pk->kp_type & ISDESC)?"D":" ");
  375. }
  376. print("\n");
  377. return 1;
  378. }
  379. static void
  380. cmd_error(const char *str, int (*print)(const char *, ...))
  381. {
  382. (void)print("%s: ISAM error %d\n", str, iserrno);
  383. }
  384. static int
  385. typeletter(int type)
  386. {
  387. switch (type) {
  388. case INTTYPE:
  389. return 'I';
  390. case LONGTYPE:
  391. return 'L';
  392. case FLOATTYPE:
  393. return 'F';
  394. case DOUBLETYPE:
  395. return 'D';
  396. case CHARTYPE:
  397. return 'C';
  398. case BINTYPE:
  399. return 'B';
  400. default:
  401. assert(0);
  402. }
  403. /* NOTREACHED */
  404. }