isvarrec.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566
  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. /*%% $XConsortium: isvarrec.c /main/3 1995/10/23 11:45:36 rswiston $ */
  28. /*
  29. * Copyright (c) 1988 by Sun Microsystems, Inc.
  30. */
  31. /*
  32. * isvarrec.c
  33. *
  34. * Description:
  35. * Fixed length record access (VLRA) module.
  36. */
  37. #include "isam_impl.h"
  38. /* Local functions */
  39. long _vl_getpos(); /* Get offset in .rec file */
  40. int _vl_deleted(); /* 0/1 returns 1 if record is deleted */
  41. static void remove_from_chain2(); /* used by _vlrec_wrrec() */
  42. long _istail_insert();
  43. static void _istail_delete();
  44. static int _istail_read();
  45. /*
  46. * _vlrec_write(fcb, record, recnum, reclen)
  47. *
  48. * Write a record.
  49. *
  50. * Input params:
  51. * FCB File Control Block
  52. * record record buffer
  53. * reclen record length (NOT USED)
  54. *
  55. * Output params:
  56. * recnum record number of the new record
  57. *
  58. * Returns 0 if record was written successfully, or -1 if any error.
  59. */
  60. /*ARGSUSED*/
  61. int
  62. _vlrec_write(Fcb *fcb, char *record, Recno *recnum, int reclen)
  63. {
  64. Recno recnum2;
  65. long rec_position;
  66. long tailoff = VL_RECNOTAIL;
  67. char recnobuf [RECNOSIZE];
  68. char tailoffbuf[LONGSIZE];
  69. /*
  70. * Reuse a deleted record if one exits.
  71. * Otherwise, extend .rec file by a record.
  72. */
  73. if (fcb->freerecno != NULL_RECNO) {
  74. recnum2 = fcb->freerecno;
  75. /*
  76. * Remove record from the chain of deleted records.
  77. */
  78. rec_position = _vl_getpos(fcb, recnum2); /* Offset in .rec file */
  79. _cp_fromfile(fcb, fcb->datfd, recnobuf, rec_position + LONGSIZE, RECNOSIZE);
  80. fcb->freerecno = ldrecno(recnobuf);
  81. }
  82. else {
  83. recnum2 = ++(fcb->lastrecno);
  84. /*
  85. * Extend .rec file size if necessary.
  86. */
  87. while (_vl_getpos(fcb, recnum2 + 1) > fcb->datsize * ISPAGESIZE) {
  88. fcb->datsize = _extend_file(fcb, fcb->datfd, fcb->datsize);
  89. }
  90. rec_position = _vl_getpos(fcb, recnum2); /* Offset in .rec file */
  91. }
  92. /*
  93. * Store variable part of record (the 'tail') in .var file.
  94. */
  95. tailoff = _istail_insert(fcb, record + fcb->minreclen,
  96. reclen - fcb->minreclen);
  97. /*
  98. * Copy record to the .rec file. Mark record as undeleted.
  99. */
  100. stlong(tailoff, tailoffbuf);
  101. _cp_tofile(fcb, fcb->datfd, tailoffbuf, rec_position, LONGSIZE);
  102. _cp_tofile(fcb, fcb->datfd, record, rec_position + LONGSIZE, fcb->minreclen);
  103. *recnum = recnum2;
  104. return (ISOK);
  105. }
  106. /*
  107. * _vlrec_read(fcb, record, recnum, reclen)
  108. *
  109. * Read a record.
  110. *
  111. * Input params:
  112. * FCB File Control Block
  113. * recnum record number of the record
  114. * reclen filled with the record size for compatibilty with
  115. * variable length records
  116. *
  117. * Output params:
  118. * record record buffer is filled with data
  119. *
  120. * Returns 0 if record was read successfully, or error code if any error.
  121. */
  122. int
  123. _vlrec_read(Fcb *fcb, char *record, Recno recnum, int *reclen)
  124. {
  125. long rec_position;
  126. long tailoff;
  127. char tailoffbuf[LONGSIZE];
  128. /*
  129. * Check that recnum is within the range of existing record numbers.
  130. */
  131. if (recnum < 1 || recnum > fcb->lastrecno)
  132. return (EENDFILE);
  133. rec_position = _vl_getpos(fcb, recnum); /* Offset in .rec file */
  134. /*
  135. * Check that the record is not marked as deleted.
  136. */
  137. _cp_fromfile(fcb, fcb->datfd, tailoffbuf, rec_position, LONGSIZE);
  138. tailoff = ldlong(tailoffbuf);
  139. if (tailoff == VL_RECDELETED) {
  140. return (ENOREC);
  141. }
  142. /*
  143. * Copy record from the .at file.
  144. */
  145. _cp_fromfile(fcb, fcb->datfd, record, rec_position + LONGSIZE, fcb->minreclen);
  146. *reclen = fcb->minreclen;
  147. /*
  148. * Get the 'tail' of the record if any.
  149. */
  150. *reclen += _istail_read(fcb, tailoff, record + fcb->minreclen);
  151. if (*reclen > fcb->maxreclen)
  152. _isfatal_error("Corrupted file: too long variable length record");
  153. return (ISOK);
  154. }
  155. /*
  156. * pos = _vl_getpos(fcb, recnum)
  157. *
  158. * Calculate the position of record in .rec file.
  159. */
  160. long
  161. _vl_getpos(Fcb *fcb, Recno recnum)
  162. {
  163. return ((long)(ISCNTLSIZE + (fcb->minreclen + LONGSIZE) * (recnum -1)));
  164. }
  165. /*
  166. * _vlrec_rewrite(fcb, record, recnum, reclen)
  167. *
  168. * Rewrite a record.
  169. *
  170. * Input params:
  171. * FCB File Control Block
  172. * recnum record number of the record
  173. * record new record
  174. * int reclen (NOT USED)
  175. *
  176. * Returns 0 if record was rewritten successfully, or error code if any error.
  177. */
  178. /*ARGSUSED*/
  179. int
  180. _vlrec_rewrite(Fcb *fcb, char *record, Recno recnum, int reclen)
  181. {
  182. long rec_position;
  183. long tailoff;
  184. char tailoffbuf[LONGSIZE];
  185. /*
  186. * Check that recnum is within the range of existing record numbers.
  187. */
  188. if (recnum < 1 || recnum > fcb->lastrecno)
  189. return (EENDFILE);
  190. rec_position = _vl_getpos(fcb, recnum); /* Offset in .rec file */
  191. /*
  192. * Check that the record is not marked as deleted.
  193. */
  194. _cp_fromfile(fcb, fcb->datfd, tailoffbuf, rec_position, LONGSIZE);
  195. tailoff = ldlong(tailoffbuf);
  196. if (tailoff == VL_RECDELETED) {
  197. return (ENOREC);
  198. }
  199. /*
  200. * Store variable part of record (the 'tail') in .var file.
  201. */
  202. tailoff = _istail_modify(fcb, tailoff, record + fcb->minreclen,
  203. reclen - fcb->minreclen);
  204. /*
  205. * Copy new record to the .rec file.
  206. */
  207. stlong(tailoff, tailoffbuf);
  208. _cp_tofile(fcb, fcb->datfd, tailoffbuf, rec_position, LONGSIZE);
  209. _cp_tofile(fcb, fcb->datfd, record, rec_position + LONGSIZE, fcb->minreclen);
  210. return (ISOK);
  211. }
  212. /*
  213. * _vlrec_delete;(fcb, recnum)
  214. *
  215. * Rewrite a record.
  216. *
  217. * Input params:
  218. * FCB File Control Block
  219. * recnum record number of the record
  220. *
  221. * Returns 0 if record was rewritten successfully, or error code if any error.
  222. */
  223. int
  224. _vlrec_delete(Fcb *fcb, Recno recnum)
  225. {
  226. long rec_position;
  227. long tailoff;
  228. char tailoffbuf[LONGSIZE];
  229. char recnobuf [RECNOSIZE];
  230. /*
  231. * Check that recnum is within the range of existing record numbers.
  232. */
  233. if (recnum < 1 || recnum > fcb->lastrecno)
  234. return (EENDFILE);
  235. rec_position = _vl_getpos(fcb, recnum); /* Offset in .rec file */
  236. /*
  237. * Check that the record is not marked as deleted.
  238. */
  239. _cp_fromfile(fcb, fcb->datfd, tailoffbuf, rec_position, LONGSIZE);
  240. tailoff = ldlong(tailoffbuf);
  241. if (tailoff == VL_RECDELETED) {
  242. return (ENOREC);
  243. }
  244. /*
  245. * Set the delete flag to VL_RECDELETED.
  246. */
  247. tailoff = VL_RECDELETED;
  248. stlong(tailoff, tailoffbuf);
  249. _cp_tofile(fcb, fcb->datfd, tailoffbuf, rec_position, LONGSIZE);
  250. /*
  251. * Insert record into chain of deleted records.
  252. */
  253. strecno(fcb->freerecno, recnobuf);
  254. _cp_tofile(fcb, fcb->datfd, recnobuf, rec_position + LONGSIZE, RECNOSIZE);
  255. fcb->freerecno = recnum;
  256. /*
  257. * Delete tail from .var file.
  258. */
  259. return (ISOK);
  260. }
  261. /*
  262. * _vlrec_wrrec(fcb, record, recnum, reclen)
  263. *
  264. * Write a record by record number.
  265. *
  266. * Input params:
  267. * FCB File Control Block
  268. * recnum record number of the record
  269. * record record buffer
  270. * int reclen (NOT USED)
  271. *
  272. * Returns 0 if record was written successfully, or error code if any error.
  273. *
  274. * Note that _vlrec_wrrec() commits updates and syncs the FCB to avoid
  275. * buffer pool overflow.
  276. */
  277. /*ARGSUSED*/
  278. int
  279. _vlrec_wrrec(Fcb *fcb, char *record, Recno recnum, int reclen)
  280. {
  281. long rec_position;
  282. long tailoff;
  283. char tailoffbuf[LONGSIZE];
  284. Recno recnum2;
  285. char recnumbuf [RECNOSIZE];
  286. /*
  287. * Check that recnum is not negative.
  288. */
  289. if (recnum < 1)
  290. return (EBADARG);
  291. rec_position = _vl_getpos(fcb, recnum); /* Offset in .rec file */
  292. if (recnum > fcb->lastrecno) {
  293. /*
  294. * If the recnum is bigger than the highest record number in the .rec
  295. * file, extend the .rec file.
  296. */
  297. while (_vl_getpos(fcb, recnum + 1) > fcb->datsize * ISPAGESIZE) {
  298. fcb->datsize = _extend_file(fcb, fcb->datfd, fcb->datsize);
  299. /* Sync the updates to avoid buffer pool overflow. */
  300. _isdisk_commit();
  301. _isdisk_sync();
  302. (void)_isfcb_cntlpg_w2(fcb);
  303. }
  304. /*
  305. * Mark all records in the range <fcb->lastrecno+1, recnum> as
  306. * deleted.
  307. */
  308. tailoff = VL_RECDELETED;
  309. stlong(tailoff, tailoffbuf);
  310. for (recnum2 = fcb->lastrecno + 1; recnum2 <= recnum; recnum2++) {
  311. _cp_tofile(fcb, fcb->datfd, tailoffbuf, _vl_getpos(fcb, recnum2), LONGSIZE);
  312. strecno(fcb->freerecno, recnumbuf);
  313. _cp_tofile(fcb, fcb->datfd, recnumbuf,
  314. _vl_getpos(fcb, recnum2) + LONGSIZE, RECNOSIZE);
  315. fcb->freerecno = recnum2;
  316. /* Sync the updates to avoid buffer pool overflow. */
  317. _isdisk_commit();
  318. _isdisk_sync();
  319. fcb->lastrecno = recnum;
  320. (void)_isfcb_cntlpg_w2(fcb);
  321. }
  322. /*
  323. * Note that the disk structures are in a consistent state now,
  324. * the .rec was extended by a few records marked as 'deleted'.
  325. * This is important for subsequent rollbacks.
  326. */
  327. }
  328. /*
  329. * If recnum specifies a record that has existed, check whether it
  330. * has been deleted. _vlrec_wrrec() does not override existing record.
  331. */
  332. _cp_fromfile(fcb, fcb->datfd, tailoffbuf, rec_position, LONGSIZE);
  333. tailoff = ldlong(tailoffbuf);
  334. if (tailoff != VL_RECDELETED) {
  335. return (EDUPL);
  336. }
  337. /*
  338. * Remove the record from the chain of deleted records.
  339. */
  340. remove_from_chain2(fcb, recnum);
  341. /*
  342. * Store variable part of record (the 'tail') in .var file.
  343. */
  344. tailoff = _istail_insert(fcb, record + fcb->minreclen, reclen - fcb->minreclen);
  345. /*
  346. * Copy new record to the .rec file.
  347. */
  348. stlong(tailoff, tailoffbuf);
  349. _cp_tofile(fcb, fcb->datfd, tailoffbuf, rec_position, LONGSIZE);
  350. _cp_tofile(fcb, fcb->datfd, record, rec_position + LONGSIZE, fcb->minreclen);
  351. return (ISOK);
  352. }
  353. /*
  354. * remove_from_chain(fcb, recnum)
  355. *
  356. * Remove record from the chain of deleted records.
  357. */
  358. static void
  359. remove_from_chain2(Fcb *fcb, Recno recnum)
  360. {
  361. char recnobuf1 [RECNOSIZE] , recnobuf2 [RECNOSIZE];
  362. long pos1, pos2;
  363. Recno recnum2;
  364. pos1 = _vl_getpos(fcb, recnum);
  365. _cp_fromfile(fcb, fcb->datfd, recnobuf1, pos1 + LONGSIZE, RECNOSIZE);
  366. if (fcb->freerecno == recnum) {
  367. fcb->freerecno = ldrecno(recnobuf1);
  368. }
  369. else {
  370. recnum2 = fcb->freerecno;
  371. do {
  372. pos2 = _vl_getpos(fcb, recnum2);
  373. _cp_fromfile(fcb, fcb->datfd, recnobuf2, pos2 + LONGSIZE, RECNOSIZE);
  374. recnum2 = ldrecno(recnobuf2);
  375. } while (recnum2 != recnum && recnum2 != NULL_RECNO);
  376. _cp_tofile(fcb, fcb->datfd, recnobuf1, pos2 + LONGSIZE, RECNOSIZE);
  377. }
  378. }
  379. /*
  380. * The following are functions that manipulate the 'tails' of variable
  381. * records. The tail is the actual record with the fixed part removed
  382. * (fixed part starts at offset zero and its length is minimum record
  383. * length. The tails are stored in the .var file.
  384. */
  385. /* Insert tail into .var file. Return offset in .var file */
  386. long _istail_insert(Fcb *fcb, char *tailp, int taillen)
  387. {
  388. char frameheadbuf [2 * SHORTSIZE];
  389. int framelen;
  390. long offset;
  391. /* printf ("_insert called, taillen %d\n", taillen); */
  392. if (taillen == 0)
  393. return (VL_RECNOTAIL);
  394. framelen = taillen + 2 * SHORTSIZE;
  395. /*
  396. * Set up frame header.
  397. */
  398. stshort((short)taillen, frameheadbuf + VR_FRAMELEN_OFF);
  399. stshort((short)taillen, frameheadbuf + VR_TAILLEN_OFF);
  400. offset = fcb->varend;
  401. /*
  402. * Extend .var file if that is necesary.
  403. */
  404. while (offset + framelen > fcb->varsize * ISPAGESIZE)
  405. fcb->varsize = _extend_file(fcb, fcb->varfd, fcb->varsize);
  406. /*
  407. * Copy frame head and tail to .var file.
  408. */
  409. _cp_tofile(fcb, fcb->varfd, frameheadbuf, offset, 2 * SHORTSIZE);
  410. _cp_tofile(fcb, fcb->varfd, tailp, offset + 2 * SHORTSIZE, taillen);
  411. fcb->varend += taillen + 2 * SHORTSIZE;
  412. return (offset);
  413. }
  414. /* Remove tail from .var file */
  415. /* ARGSUSED */
  416. Static void _istail_delete(Fcb *fcb, long offset)
  417. {
  418. /*
  419. * Don't do anything in NetISAM 1.0. The tails are lost, the space
  420. * will be re-used after next restructuring: "copy -c file" command
  421. */
  422. return;
  423. }
  424. /* Read tail from .var file */
  425. Static int _istail_read(Fcb *fcb, long offset, char *buffer)
  426. {
  427. char frameheadbuf [2 * SHORTSIZE];
  428. int taillen;
  429. /* printf ("_read called, offset %d\n", offset); */
  430. if (offset == VL_RECNOTAIL)
  431. return (0);
  432. /*
  433. * Read frame header.
  434. */
  435. _cp_fromfile(fcb, fcb->varfd, frameheadbuf, offset, 2 * SHORTSIZE);
  436. taillen = ldshort(frameheadbuf + VR_TAILLEN_OFF);
  437. _cp_fromfile(fcb, fcb->varfd, buffer, offset + 2 * SHORTSIZE, taillen);
  438. return (taillen);
  439. }
  440. /* Rewrite tail. Returns -1 if the new tail is longer than the original frame */
  441. int _istail_modify(Fcb *fcb, long offset, char *tailp, int taillen)
  442. {
  443. char frameheadbuf [2 * SHORTSIZE];
  444. int framelen;
  445. /*
  446. * Trivial case: no old frame, no new tail.
  447. */
  448. if (offset == VL_RECNOTAIL && taillen == 0)
  449. return (offset);
  450. if (offset != VL_RECNOTAIL) {
  451. /*
  452. * Read frame header.
  453. */
  454. _cp_fromfile(fcb, fcb->varfd, frameheadbuf, offset, 2 * SHORTSIZE);
  455. framelen = ldshort(frameheadbuf + VR_FRAMELEN_OFF);
  456. }
  457. else
  458. framelen = 0;
  459. if (taillen > framelen) {
  460. /*
  461. * Delete the old frame if the new tail does not fit.
  462. * Insert the new tail at the end of .var file.
  463. */
  464. _istail_delete(fcb, offset);
  465. return (_istail_insert(fcb, tailp, taillen));
  466. }
  467. else {
  468. /*
  469. * The new tail fits in the existing frame.
  470. */
  471. stshort((short)taillen, frameheadbuf + VR_TAILLEN_OFF);
  472. _cp_tofile(fcb, fcb->varfd, frameheadbuf, offset, 2 * SHORTSIZE);
  473. _cp_tofile(fcb, fcb->varfd, tailp, offset + 2 * SHORTSIZE, taillen);
  474. return (offset);
  475. }
  476. }