68d20e9d86d87e30edf1ec383a39f630dc7f7284
[oweals/cde.git] / cde / lib / tt / mini_isam / isfixrec.c
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: isfixrec.c /main/3 1995/10/23 11:39:42 rswiston $                                                    */
28 #ifndef lint
29 static char sccsid[] = "@(#)isfixrec.c 1.5 89/07/17 Copyr 1988 Sun Micro";
30 #endif
31 /*
32  * Copyright (c) 1988 by Sun Microsystems, Inc.
33  */
34
35 /*
36  * isfixrec.c
37  *
38  * Description:
39  *      Fixed length record access (FLRA) module.
40  */
41
42 #include "isam_impl.h"
43
44 /* Local functions */
45 long _fl_getpos();                           /* Get offset in .rec file */
46 int  _fl_deleted();                          /* 0/1 returns 1 if record is deleted */
47 static void remove_from_chain();             /* used by _flrec_wrrec() */
48
49 /*
50  * _flrec_write(fcb, record, recnum, reclen)
51  *
52  * Write a record.
53  *
54  * Input params:
55  *      FCB     File Control Block
56  *      record  record buffer
57  *      reclen  record length (NOT USED)
58  *
59  * Output params:
60  *      recnum  record number of the new record
61  *
62  * Returns 0 if record was written successfully, or -1 if any error.
63  */
64
65 /*ARGSUSED*/
66 int
67 _flrec_write(register Fcb *fcb, char *record, Recno *recnum, int reclen)
68 {
69     Recno               recnum2;
70     long                rec_position;
71     char                delflag = FL_RECEXISTS;
72     char                recnobuf [RECNOSIZE];
73
74     /*
75      * Reuse a deleted record if one exits.
76      * Otherwise, extend .rec file by a record.
77      */
78     if (fcb->freerecno != NULL_RECNO) {
79         recnum2 = fcb->freerecno;
80
81         /*
82          * Remove record from the chain of deleted records.
83          */
84         rec_position = _fl_getpos(fcb, recnum2); /* Offset in .rec file */
85         _cp_fromfile(fcb, fcb->datfd, recnobuf, rec_position + 1, RECNOSIZE);
86         fcb->freerecno = ldrecno(recnobuf);
87     }
88     else {
89         recnum2 = ++(fcb->lastrecno);
90
91         /* 
92          * Extend .rec file size if necessary.
93          */
94         while (_fl_getpos(fcb, recnum2 + 1) > fcb->datsize * ISPAGESIZE) {
95             fcb->datsize = _extend_file(fcb, fcb->datfd, fcb->datsize);
96         }
97         rec_position = _fl_getpos(fcb, recnum2); /* Offset in .rec file */
98     }
99
100
101     /*
102      * Copy record to the .at file. Mark record as undeleted.
103      */
104     _cp_tofile(fcb, fcb->datfd, &delflag, rec_position, 1); 
105     _cp_tofile(fcb, fcb->datfd, record, rec_position + 1, fcb->minreclen); 
106
107     *recnum = recnum2;
108
109     return (ISOK);
110 }
111
112 /*
113  * _flrec_read(fcb, record, recnum, reclen)
114  *
115  * Read a record.
116  *
117  * Input params:
118  *      FCB     File Control Block
119  *      recnum  record number of the record
120  *      reclen  filled with the record size for compatibilty with
121  *              variable length records
122  *
123  * Output params:
124  *      record  record buffer is filled with data
125  *
126  * Returns 0 if record was read successfully, or error code if any error.
127  */
128
129 int
130 _flrec_read(register Fcb *fcb, char *record, Recno recnum, int *reclen)
131 {
132     long                rec_position;
133     char                delflag;
134
135     /*
136      * Check that recnum is within the range of existing record numbers.
137      */
138     if (recnum < 1 || recnum > fcb->lastrecno)
139         return (EENDFILE);
140
141     rec_position = _fl_getpos(fcb, recnum); /* Offset in .rec file */
142
143     /*
144      * Check that the record is not marked as deleted.
145      */
146     _cp_fromfile(fcb, fcb->datfd, &delflag, rec_position, 1); 
147     if (delflag == FL_RECDELETED) {
148         return (ENOREC);
149     }
150
151     /*
152      * Copy record from the .at file. 
153      */
154     _cp_fromfile(fcb, fcb->datfd, record, rec_position + 1, fcb->minreclen); 
155
156     *reclen = fcb->minreclen;
157
158     return (ISOK);
159 }
160
161 /*
162  * pos = _fl_getpos(fcb, recnum)
163  *
164  * Calculate the position of record in .rec file.
165  */
166
167 long
168 _fl_getpos(Fcb *fcb, Recno recnum)
169 {
170     return ((long)(ISCNTLSIZE + (fcb->minreclen + 1) * (recnum -1)));
171 }
172
173 /*
174  * _flrec_rewrite(fcb, record, recnum, reclen)
175  *
176  * Rewrite a record.
177  *
178  * Input params:
179  *      FCB     File Control Block
180  *      recnum  record number of the record
181  *      record  new record
182  *      int     reclen (NOT USED)
183  *
184  * Returns 0 if record was rewritten successfully, or error code if any error.
185  */
186
187 /*ARGSUSED*/
188 int
189 _flrec_rewrite(register Fcb *fcb, char *record, Recno recnum, int reclen)
190 {
191     long                rec_position;
192     char                delflag;
193
194     /*
195      * Check that recnum is within the range of existing record numbers.
196      */
197     if (recnum < 1 || recnum > fcb->lastrecno)
198         return (EENDFILE);
199
200     rec_position = _fl_getpos(fcb, recnum); /* Offset in .rec file */
201
202     /*
203      * Check that the record is not marked as deleted.
204      */
205     _cp_fromfile(fcb, fcb->datfd, &delflag, rec_position, 1); 
206     if (delflag == FL_RECDELETED) {
207         return (ENOREC);
208     }
209
210     /*
211      * Copy new record to the .rec file. 
212      */
213     _cp_tofile(fcb, fcb->datfd, record, rec_position + 1, fcb->minreclen); 
214
215     return (ISOK);
216 }
217
218 /*
219  * _flrec_delete(fcb, recnum)
220  *
221  * Rewrite a record.
222  *
223  * Input params:
224  *      FCB     File Control Block
225  *      recnum  record number of the record
226  *
227  * Returns 0 if record was rewritten successfully, or error code if any error.
228  */
229
230 int
231 _flrec_delete(register Fcb *fcb, Recno recnum)
232 {
233     long                rec_position;
234     char                delflag;
235     char                recnobuf [RECNOSIZE];
236
237     /*
238      * Check that recnum is within the range of existing record numbers.
239      */
240     if (recnum < 1 || recnum > fcb->lastrecno)
241         return (EENDFILE);
242
243     rec_position = _fl_getpos(fcb, recnum); /* Offset in .rec file */
244
245     /*
246      * Check that the record is not marked as deleted.
247      */
248     _cp_fromfile(fcb, fcb->datfd, &delflag, rec_position, 1); 
249     if (delflag == FL_RECDELETED) {
250         return (ENOREC);
251     }
252
253     /*
254      * Set the delete flag to FL_RECDELETED.
255      */
256     delflag = FL_RECDELETED;
257     _cp_tofile(fcb, fcb->datfd, &delflag, rec_position, 1);
258
259     /*
260      * Insert record into chain of deleted records.
261      */
262     strecno(fcb->freerecno, recnobuf);
263     _cp_tofile(fcb, fcb->datfd, recnobuf, rec_position + 1, RECNOSIZE);
264     fcb->freerecno = recnum;
265
266     return (ISOK);
267 }
268
269 /*
270  * _flrec_wrrec(fcb, record, recnum, reclen)
271  *
272  * Write a record by record number.
273  *
274  * Input params:
275  *      FCB     File Control Block
276  *      recnum  record number of the record
277  *      record  record buffer
278  *      int     reclen (NOT USED)
279  *
280  * Returns 0 if record was written successfully, or error code if any error.
281  *
282  * Note that _flrec_wrrec() commits updates and syncs the FCB to avoid
283  *      buffer pool overflow.
284  */
285
286 /*ARGSUSED*/
287 int
288 _flrec_wrrec(register Fcb *fcb, char *record, Recno recnum, int reclen)
289 {
290     long                rec_position;
291     char                delflag;
292     Recno               recnum2;
293     char                recnumbuf [RECNOSIZE];
294
295     /*
296      * Check that recnum is not negative.
297      */
298     if (recnum < 1)
299         return (EBADARG);
300
301     rec_position = _fl_getpos(fcb, recnum); /* Offset in .rec file */
302
303     if (recnum > fcb->lastrecno)  {
304
305         /*
306          * If the recnum is bigger than the highest record number in the .rec
307          * file, extend the .rec file.
308          */
309         while (_fl_getpos(fcb, recnum + 1) > fcb->datsize * ISPAGESIZE) {
310             fcb->datsize = _extend_file(fcb, fcb->datfd, fcb->datsize);
311             
312             /* Sync the updates to avoid buffer pool overflow. */
313             _isdisk_commit();
314             _isdisk_sync();
315             (void)_isfcb_cntlpg_w2(fcb);
316         }
317
318         /*
319          * Mark all records in the range <fcb->lastrecno+1, recnum>  as
320          * deleted.
321          */
322         delflag = FL_RECDELETED;
323         for (recnum2 = fcb->lastrecno + 1; recnum2 <= recnum; recnum2++) {      
324             _cp_tofile(fcb, fcb->datfd, &delflag, _fl_getpos(fcb, recnum2), 1); 
325             strecno(fcb->freerecno, recnumbuf);
326             _cp_tofile(fcb, fcb->datfd, recnumbuf,
327                        _fl_getpos(fcb, recnum2) + 1, RECNOSIZE); 
328             fcb->freerecno = recnum2;
329             
330             /* Sync the updates to avoid buffer pool overflow. */
331             _isdisk_commit();
332             _isdisk_sync();
333             fcb->lastrecno = recnum;
334             (void)_isfcb_cntlpg_w2(fcb);
335         }
336         
337         /*
338          * Note that the disk structures are in a consistent state now,
339          * the .rec was extended by a few records marked as 'deleted'.
340          * This is important for subsequent rollbacks.
341          */
342     } 
343
344     /*
345      * If recnum specifies a record that has existed, check whether it
346      * has been deleted. _flrec_wrrec() does not override existing record.
347      */
348     _cp_fromfile(fcb, fcb->datfd, &delflag, rec_position, 1); 
349     if (delflag == FL_RECEXISTS) {
350         return (EDUPL);
351     }
352
353     /*
354      * Remove the record from the chain of deleted records.
355      */
356     remove_from_chain(fcb, recnum);
357
358     /*
359      * Copy new record to the .rec file. 
360      */
361     delflag = FL_RECEXISTS;
362     _cp_tofile(fcb, fcb->datfd, &delflag, rec_position, 1); 
363     _cp_tofile(fcb, fcb->datfd, record, rec_position + 1, fcb->minreclen); 
364
365     return (ISOK);
366 }
367
368 /*
369  * remvoe_from_chain(fcb, recnum)
370  *
371  * Remove record from the chain of deleted records.
372  */
373
374 static void
375 remove_from_chain(Fcb *fcb, Recno recnum)
376 {
377     char                recnobuf1 [RECNOSIZE] , recnobuf2 [RECNOSIZE];
378     long                pos1, pos2;
379     Recno               recnum2;
380
381     pos1 = _fl_getpos(fcb, recnum);
382     _cp_fromfile(fcb, fcb->datfd, recnobuf1, pos1 + 1, RECNOSIZE); 
383
384     if (fcb->freerecno == recnum) {
385         fcb->freerecno = ldrecno(recnobuf1);
386     }
387     else {
388         recnum2 = fcb->freerecno;
389         do {
390             pos2 = _fl_getpos(fcb, recnum2);
391             _cp_fromfile(fcb, fcb->datfd, recnobuf2, pos2 + 1, RECNOSIZE); 
392             recnum2 = ldrecno(recnobuf2);
393         } while (recnum2 != recnum && recnum2 != NULL_RECNO);
394
395         _cp_tofile(fcb, fcb->datfd, recnobuf1, pos2 + 1, RECNOSIZE); 
396     }
397 }