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