1 |
|
|
/* $OpenBSD: pass1.c,v 1.45 2017/04/12 15:23:08 millert Exp $ */ |
2 |
|
|
/* $NetBSD: pass1.c,v 1.16 1996/09/27 22:45:15 christos Exp $ */ |
3 |
|
|
|
4 |
|
|
/* |
5 |
|
|
* Copyright (c) 1980, 1986, 1993 |
6 |
|
|
* The Regents of the University of California. All rights reserved. |
7 |
|
|
* |
8 |
|
|
* Redistribution and use in source and binary forms, with or without |
9 |
|
|
* modification, are permitted provided that the following conditions |
10 |
|
|
* are met: |
11 |
|
|
* 1. Redistributions of source code must retain the above copyright |
12 |
|
|
* notice, this list of conditions and the following disclaimer. |
13 |
|
|
* 2. Redistributions in binary form must reproduce the above copyright |
14 |
|
|
* notice, this list of conditions and the following disclaimer in the |
15 |
|
|
* documentation and/or other materials provided with the distribution. |
16 |
|
|
* 3. Neither the name of the University nor the names of its contributors |
17 |
|
|
* may be used to endorse or promote products derived from this software |
18 |
|
|
* without specific prior written permission. |
19 |
|
|
* |
20 |
|
|
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND |
21 |
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
22 |
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
23 |
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
24 |
|
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
25 |
|
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
26 |
|
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
27 |
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
28 |
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
29 |
|
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
30 |
|
|
* SUCH DAMAGE. |
31 |
|
|
*/ |
32 |
|
|
|
33 |
|
|
#include <sys/param.h> /* MIN setbit btodb isset */ |
34 |
|
|
#include <sys/time.h> |
35 |
|
|
#include <ufs/ufs/dinode.h> |
36 |
|
|
#include <ufs/ufs/dir.h> |
37 |
|
|
#include <ufs/ffs/fs.h> |
38 |
|
|
|
39 |
|
|
#include <stdio.h> |
40 |
|
|
#include <stdlib.h> |
41 |
|
|
#include <string.h> |
42 |
|
|
#include <unistd.h> |
43 |
|
|
#include <limits.h> |
44 |
|
|
|
45 |
|
|
#include "fsck.h" |
46 |
|
|
#include "extern.h" |
47 |
|
|
#include "fsutil.h" |
48 |
|
|
|
49 |
|
|
static daddr_t badblk; |
50 |
|
|
static daddr_t dupblk; |
51 |
|
|
static void checkinode(ino_t, struct inodesc *); |
52 |
|
|
|
53 |
|
|
static ino_t info_inumber; |
54 |
|
|
|
55 |
|
|
static int |
56 |
|
|
pass1_info(char *buf, size_t buflen) |
57 |
|
|
{ |
58 |
|
|
return (snprintf(buf, buflen, "phase 1, inode %llu/%llu", |
59 |
|
|
(unsigned long long)info_inumber, |
60 |
|
|
(unsigned long long)sblock.fs_ipg * sblock.fs_ncg) > 0); |
61 |
|
|
} |
62 |
|
|
|
63 |
|
|
void |
64 |
|
|
pass1(void) |
65 |
|
|
{ |
66 |
|
|
ino_t inumber, inosused, ninosused; |
67 |
|
|
size_t inospace; |
68 |
|
|
struct inostat *info; |
69 |
|
|
int c; |
70 |
|
16 |
struct inodesc idesc; |
71 |
|
|
daddr_t i, cgd; |
72 |
|
|
u_int8_t *cp; |
73 |
|
|
|
74 |
|
|
/* |
75 |
|
|
* Set file system reserved blocks in used block map. |
76 |
|
|
*/ |
77 |
✓✓ |
40 |
for (c = 0; c < sblock.fs_ncg; c++) { |
78 |
|
12 |
cgd = cgdmin(&sblock, c); |
79 |
✓✓ |
12 |
if (c == 0) |
80 |
|
8 |
i = cgbase(&sblock, c); |
81 |
|
|
else |
82 |
|
4 |
i = cgsblock(&sblock, c); |
83 |
✓✓ |
1596 |
for (; i < cgd; i++) |
84 |
|
792 |
setbmap(i); |
85 |
|
|
} |
86 |
|
8 |
i = sblock.fs_csaddr; |
87 |
|
8 |
cgd = i + howmany(sblock.fs_cssize, sblock.fs_fsize); |
88 |
✓✓ |
32 |
for (; i < cgd; i++) |
89 |
|
8 |
setbmap(i); |
90 |
|
|
/* |
91 |
|
|
* Find all allocated blocks. |
92 |
|
|
*/ |
93 |
|
8 |
memset(&idesc, 0, sizeof(struct inodesc)); |
94 |
|
8 |
idesc.id_type = ADDR; |
95 |
|
8 |
idesc.id_func = pass1check; |
96 |
|
8 |
n_files = n_blks = 0; |
97 |
|
8 |
info_inumber = 0; |
98 |
|
8 |
info_fn = pass1_info; |
99 |
✓✓ |
40 |
for (c = 0; c < sblock.fs_ncg; c++) { |
100 |
|
12 |
inumber = c * sblock.fs_ipg; |
101 |
|
12 |
setinodebuf(inumber); |
102 |
|
12 |
getblk(&cgblk, cgtod(&sblock, c), sblock.fs_cgsize); |
103 |
✗✓ |
12 |
if (sblock.fs_magic == FS_UFS2_MAGIC) { |
104 |
|
|
inosused = cgrp.cg_initediblk; |
105 |
|
|
if (inosused > sblock.fs_ipg) |
106 |
|
|
inosused = sblock.fs_ipg; |
107 |
|
|
} else |
108 |
|
12 |
inosused = sblock.fs_ipg; |
109 |
|
|
|
110 |
|
|
/* |
111 |
|
|
* If we are using soft updates, then we can trust the |
112 |
|
|
* cylinder group inode allocation maps to tell us which |
113 |
|
|
* inodes are allocated. We will scan the used inode map |
114 |
|
|
* to find the inodes that are really in use, and then |
115 |
|
|
* read only those inodes in from disk. |
116 |
|
|
*/ |
117 |
✗✓✗✗
|
12 |
if (preen && usedsoftdep) { |
118 |
|
|
cp = &cg_inosused(&cgrp)[(inosused - 1) / CHAR_BIT]; |
119 |
|
|
for ( ; inosused != 0; cp--) { |
120 |
|
|
if (*cp == 0) { |
121 |
|
|
if (inosused > CHAR_BIT) |
122 |
|
|
inosused -= CHAR_BIT; |
123 |
|
|
else |
124 |
|
|
inosused = 0; |
125 |
|
|
continue; |
126 |
|
|
} |
127 |
|
|
for (i = 1 << (CHAR_BIT - 1); i > 0; i >>= 1) { |
128 |
|
|
if (*cp & i) |
129 |
|
|
break; |
130 |
|
|
inosused--; |
131 |
|
|
} |
132 |
|
|
break; |
133 |
|
|
} |
134 |
|
|
} |
135 |
|
|
/* |
136 |
|
|
* Allocate inoinfo structures for the allocated inodes. |
137 |
|
|
*/ |
138 |
|
12 |
inostathead[c].il_numalloced = inosused; |
139 |
✗✓ |
12 |
if (inosused == 0) { |
140 |
|
|
inostathead[c].il_stat = 0; |
141 |
|
|
continue; |
142 |
|
|
} |
143 |
|
12 |
info = calloc((unsigned)inosused, sizeof(struct inostat)); |
144 |
|
12 |
inospace = (unsigned)inosused * sizeof(struct inostat); |
145 |
✗✓ |
12 |
if (info == NULL) |
146 |
|
|
errexit("cannot alloc %zu bytes for inoinfo", inospace); |
147 |
|
12 |
inostathead[c].il_stat = info; |
148 |
|
|
/* |
149 |
|
|
* Scan the allocated inodes. |
150 |
|
|
*/ |
151 |
✓✓ |
2008 |
for (i = 0; i < inosused; i++, inumber++) { |
152 |
|
992 |
info_inumber = inumber; |
153 |
✓✓ |
992 |
if (inumber < ROOTINO) { |
154 |
|
16 |
(void)getnextinode(inumber); |
155 |
|
16 |
continue; |
156 |
|
|
} |
157 |
|
976 |
checkinode(inumber, &idesc); |
158 |
|
976 |
} |
159 |
|
12 |
lastino += 1; |
160 |
✓✗✓✗
|
24 |
if (inosused < sblock.fs_ipg || inumber == lastino) |
161 |
|
|
continue; |
162 |
|
|
/* |
163 |
|
|
* If we were not able to determine in advance which inodes |
164 |
|
|
* were in use, then reduce the size of the inoinfo structure |
165 |
|
|
* to the size necessary to describe the inodes that we |
166 |
|
|
* really found. |
167 |
|
|
*/ |
168 |
✓✓ |
12 |
if (lastino < (c * sblock.fs_ipg)) |
169 |
|
4 |
ninosused = 0; |
170 |
|
|
else |
171 |
|
8 |
ninosused = lastino - (c * sblock.fs_ipg); |
172 |
|
12 |
inostathead[c].il_numalloced = ninosused; |
173 |
✓✓ |
12 |
if (ninosused == 0) { |
174 |
|
4 |
free(inostathead[c].il_stat); |
175 |
|
4 |
inostathead[c].il_stat = 0; |
176 |
|
4 |
continue; |
177 |
|
|
} |
178 |
✓✗ |
8 |
if (ninosused != inosused) { |
179 |
|
|
struct inostat *ninfo; |
180 |
|
|
size_t ninospace; |
181 |
|
|
|
182 |
|
8 |
ninfo = reallocarray(info, ninosused, sizeof(*ninfo)); |
183 |
✗✓ |
8 |
if (ninfo == NULL) { |
184 |
|
|
pfatal("too many inodes %llu, or out of memory\n", |
185 |
|
|
(unsigned long long)ninosused); |
186 |
|
|
exit(8); |
187 |
|
|
} |
188 |
|
8 |
ninospace = ninosused * sizeof(*ninfo); |
189 |
✗✓ |
8 |
if (ninosused > inosused) |
190 |
|
|
memset(&ninfo[inosused], 0, ninospace - inospace); |
191 |
|
8 |
inostathead[c].il_stat = ninfo; |
192 |
|
8 |
} |
193 |
|
|
} |
194 |
|
8 |
info_fn = NULL; |
195 |
|
8 |
freeinodebuf(); |
196 |
|
8 |
} |
197 |
|
|
|
198 |
|
|
static void |
199 |
|
|
checkinode(ino_t inumber, struct inodesc *idesc) |
200 |
|
|
{ |
201 |
|
|
union dinode *dp; |
202 |
|
|
off_t kernmaxfilesize; |
203 |
|
|
struct zlncnt *zlnp; |
204 |
|
|
int ndb, j; |
205 |
|
|
mode_t mode; |
206 |
|
|
u_int64_t lndb; |
207 |
|
|
|
208 |
|
1952 |
dp = getnextinode(inumber); |
209 |
|
976 |
mode = DIP(dp, di_mode) & IFMT; |
210 |
✓✓ |
976 |
if (mode == 0) { |
211 |
✓✗✗✗
|
968 |
if ((sblock.fs_magic == FS_UFS1_MAGIC && |
212 |
|
968 |
(memcmp(dp->dp1.di_db, ufs1_zino.di_db, |
213 |
✓✗ |
968 |
NDADDR * sizeof(int32_t)) || |
214 |
|
968 |
memcmp(dp->dp1.di_ib, ufs1_zino.di_ib, |
215 |
✓✗ |
968 |
NIADDR * sizeof(int32_t)) || |
216 |
✓✗✓✗
|
1936 |
dp->dp1.di_mode || dp->dp1.di_size)) || |
217 |
✗✓ |
968 |
(sblock.fs_magic == FS_UFS2_MAGIC && |
218 |
|
|
(memcmp(dp->dp2.di_db, ufs2_zino.di_db, |
219 |
|
|
NDADDR * sizeof(daddr_t)) || |
220 |
|
|
memcmp(dp->dp2.di_ib, ufs2_zino.di_ib, |
221 |
|
|
NIADDR * sizeof(daddr_t)) || |
222 |
|
|
dp->dp2.di_mode || dp->dp2.di_size))) { |
223 |
|
|
pfatal("PARTIALLY ALLOCATED INODE I=%llu", |
224 |
|
|
(unsigned long long)inumber); |
225 |
|
|
if (reply("CLEAR") == 1) { |
226 |
|
|
dp = ginode(inumber); |
227 |
|
|
clearinode(dp); |
228 |
|
|
inodirty(); |
229 |
|
|
} |
230 |
|
|
} |
231 |
|
968 |
SET_ISTATE(inumber, USTATE); |
232 |
|
968 |
return; |
233 |
|
|
} |
234 |
|
8 |
lastino = inumber; |
235 |
|
|
/* This should match the file size limit in ffs_mountfs(). */ |
236 |
✗✓ |
24 |
kernmaxfilesize = FS_KERNMAXFILESIZE(getpagesize(), &sblock); |
237 |
✓✗✗✓
|
16 |
if (DIP(dp, di_size) > kernmaxfilesize || |
238 |
✓✗ |
8 |
DIP(dp, di_size) > sblock.fs_maxfilesize || |
239 |
✓✗ |
16 |
(mode == IFDIR && DIP(dp, di_size) > MAXDIRSIZE)) { |
240 |
|
|
if (debug) |
241 |
|
|
printf("bad size %llu:", |
242 |
|
|
(unsigned long long)DIP(dp, di_size)); |
243 |
|
|
goto unknown; |
244 |
|
|
} |
245 |
✗✓✗✗
|
8 |
if (!preen && mode == IFMT && reply("HOLD BAD BLOCK") == 1) { |
246 |
|
|
dp = ginode(inumber); |
247 |
|
|
DIP_SET(dp, di_size, sblock.fs_fsize); |
248 |
|
|
DIP_SET(dp, di_mode, IFREG|0600); |
249 |
|
|
inodirty(); |
250 |
|
|
} |
251 |
|
8 |
lndb = howmany(DIP(dp, di_size), sblock.fs_bsize); |
252 |
|
8 |
ndb = lndb > (u_int64_t)INT_MAX ? -1 : (int)lndb; |
253 |
✗✓ |
8 |
if (ndb < 0) { |
254 |
|
|
if (debug) |
255 |
|
|
printf("bad size %llu ndb %d:", |
256 |
|
|
(unsigned long long)DIP(dp, di_size), ndb); |
257 |
|
|
goto unknown; |
258 |
|
|
} |
259 |
✗✓ |
8 |
if (mode == IFBLK || mode == IFCHR) |
260 |
|
|
ndb++; |
261 |
✗✓ |
8 |
if (mode == IFLNK) { |
262 |
|
|
/* |
263 |
|
|
* Fake ndb value so direct/indirect block checks below |
264 |
|
|
* will detect any garbage after symlink string. |
265 |
|
|
*/ |
266 |
|
|
if (DIP(dp, di_size) < sblock.fs_maxsymlinklen || |
267 |
|
|
(sblock.fs_maxsymlinklen == 0 && DIP(dp, di_blocks) == 0)) { |
268 |
|
|
if (sblock.fs_magic == FS_UFS1_MAGIC) |
269 |
|
|
ndb = howmany(DIP(dp, di_size), |
270 |
|
|
sizeof(int32_t)); |
271 |
|
|
else |
272 |
|
|
ndb = howmany(DIP(dp, di_size), |
273 |
|
|
sizeof(int64_t)); |
274 |
|
|
if (ndb > NDADDR) { |
275 |
|
|
j = ndb - NDADDR; |
276 |
|
|
for (ndb = 1; j > 1; j--) |
277 |
|
|
ndb *= NINDIR(&sblock); |
278 |
|
|
ndb += NDADDR; |
279 |
|
|
} |
280 |
|
|
} |
281 |
|
|
} |
282 |
✓✓ |
192 |
for (j = ndb; j < NDADDR; j++) |
283 |
✓✗✗✓
|
264 |
if (DIP(dp, di_db[j]) != 0) { |
284 |
|
|
if (debug) |
285 |
|
|
printf("bad direct addr: %lld\n", |
286 |
|
|
(long long)DIP(dp, di_db[j])); |
287 |
|
|
goto unknown; |
288 |
|
|
} |
289 |
✗✓ |
16 |
for (j = 0, ndb -= NDADDR; ndb > 0; j++) |
290 |
|
|
ndb /= NINDIR(&sblock); |
291 |
✓✓ |
56 |
for (; j < NIADDR; j++) |
292 |
✓✗✗✓
|
72 |
if (DIP(dp, di_ib[j]) != 0) { |
293 |
|
|
if (debug) |
294 |
|
|
printf("bad indirect addr: %lld\n", |
295 |
|
|
(long long)DIP(dp, di_ib[j])); |
296 |
|
|
goto unknown; |
297 |
|
|
} |
298 |
✓✗ |
8 |
if (ftypeok(dp) == 0) |
299 |
|
|
goto unknown; |
300 |
|
8 |
n_files++; |
301 |
|
8 |
ILNCOUNT(inumber) = DIP(dp, di_nlink); |
302 |
✗✓ |
8 |
if (DIP(dp, di_nlink) <= 0) { |
303 |
|
|
zlnp = malloc(sizeof *zlnp); |
304 |
|
|
if (zlnp == NULL) { |
305 |
|
|
pfatal("LINK COUNT TABLE OVERFLOW"); |
306 |
|
|
if (reply("CONTINUE") == 0) { |
307 |
|
|
ckfini(0); |
308 |
|
|
errexit("%s", ""); |
309 |
|
|
} |
310 |
|
|
} else { |
311 |
|
|
zlnp->zlncnt = inumber; |
312 |
|
|
zlnp->next = zlnhead; |
313 |
|
|
zlnhead = zlnp; |
314 |
|
|
} |
315 |
|
|
} |
316 |
✓✗ |
8 |
if (mode == IFDIR) { |
317 |
|
8 |
if (DIP(dp, di_size) == 0) |
318 |
|
|
SET_ISTATE(inumber, DCLEAR); |
319 |
|
|
else |
320 |
|
8 |
SET_ISTATE(inumber, DSTATE); |
321 |
|
8 |
cacheino(dp, inumber); |
322 |
|
8 |
} else |
323 |
|
|
SET_ISTATE(inumber, FSTATE); |
324 |
|
8 |
SET_ITYPE(inumber, IFTODT(mode)); |
325 |
|
8 |
badblk = dupblk = 0; |
326 |
|
8 |
idesc->id_number = inumber; |
327 |
|
8 |
(void)ckinode(dp, idesc); |
328 |
|
8 |
idesc->id_entryno *= btodb(sblock.fs_fsize); |
329 |
✓✗✗✓
|
24 |
if (DIP(dp, di_blocks) != idesc->id_entryno) { |
330 |
|
|
pwarn("INCORRECT BLOCK COUNT I=%llu (%lld should be %lld)", |
331 |
|
|
(unsigned long long)inumber, (long long)DIP(dp, di_blocks), |
332 |
|
|
(long long)idesc->id_entryno); |
333 |
|
|
if (preen) |
334 |
|
|
printf(" (CORRECTED)\n"); |
335 |
|
|
else if (reply("CORRECT") == 0) |
336 |
|
|
return; |
337 |
|
|
dp = ginode(inumber); |
338 |
|
|
DIP_SET(dp, di_blocks, idesc->id_entryno); |
339 |
|
|
inodirty(); |
340 |
|
|
} |
341 |
|
8 |
return; |
342 |
|
|
unknown: |
343 |
|
|
pfatal("UNKNOWN FILE TYPE I=%llu", (unsigned long long)inumber); |
344 |
|
|
SET_ISTATE(inumber, FCLEAR); |
345 |
|
|
if (reply("CLEAR") == 1) { |
346 |
|
|
SET_ISTATE(inumber, USTATE); |
347 |
|
|
dp = ginode(inumber); |
348 |
|
|
clearinode(dp); |
349 |
|
|
inodirty(); |
350 |
|
|
} |
351 |
|
976 |
} |
352 |
|
|
|
353 |
|
|
int |
354 |
|
|
pass1check(struct inodesc *idesc) |
355 |
|
|
{ |
356 |
|
|
int res = KEEPON; |
357 |
|
|
int anyout, nfrags; |
358 |
|
16 |
daddr_t blkno = idesc->id_blkno; |
359 |
|
|
struct dups *dlp; |
360 |
|
|
struct dups *new; |
361 |
|
|
|
362 |
✗✓ |
8 |
if ((anyout = chkrange(blkno, idesc->id_numfrags)) != 0) { |
363 |
|
|
blkerror(idesc->id_number, "BAD", blkno); |
364 |
|
|
if (badblk++ >= MAXBAD) { |
365 |
|
|
pwarn("EXCESSIVE BAD BLKS I=%llu", |
366 |
|
|
(unsigned long long)idesc->id_number); |
367 |
|
|
if (preen) |
368 |
|
|
printf(" (SKIPPING)\n"); |
369 |
|
|
else if (reply("CONTINUE") == 0) { |
370 |
|
|
ckfini(0); |
371 |
|
|
errexit("%s", ""); |
372 |
|
|
} |
373 |
|
|
return (STOP); |
374 |
|
|
} |
375 |
|
|
} |
376 |
✓✓ |
32 |
for (nfrags = idesc->id_numfrags; nfrags > 0; blkno++, nfrags--) { |
377 |
✗✓✗✗
|
8 |
if (anyout && chkrange(blkno, 1)) { |
378 |
|
|
res = SKIP; |
379 |
✓✗ |
8 |
} else if (!testbmap(blkno)) { |
380 |
|
8 |
n_blks++; |
381 |
|
8 |
setbmap(blkno); |
382 |
|
8 |
} else { |
383 |
|
|
blkerror(idesc->id_number, "DUP", blkno); |
384 |
|
|
if (dupblk++ >= MAXDUP) { |
385 |
|
|
pwarn("EXCESSIVE DUP BLKS I=%llu", |
386 |
|
|
(unsigned long long)idesc->id_number); |
387 |
|
|
if (preen) |
388 |
|
|
printf(" (SKIPPING)\n"); |
389 |
|
|
else if (reply("CONTINUE") == 0) { |
390 |
|
|
ckfini(0); |
391 |
|
|
errexit("%s", ""); |
392 |
|
|
} |
393 |
|
|
return (STOP); |
394 |
|
|
} |
395 |
|
|
new = malloc(sizeof(struct dups)); |
396 |
|
|
if (new == NULL) { |
397 |
|
|
pfatal("DUP TABLE OVERFLOW."); |
398 |
|
|
if (reply("CONTINUE") == 0) { |
399 |
|
|
ckfini(0); |
400 |
|
|
errexit("%s", ""); |
401 |
|
|
} |
402 |
|
|
return (STOP); |
403 |
|
|
} |
404 |
|
|
new->dup = blkno; |
405 |
|
|
if (muldup == 0) { |
406 |
|
|
duplist = muldup = new; |
407 |
|
|
new->next = 0; |
408 |
|
|
} else { |
409 |
|
|
new->next = muldup->next; |
410 |
|
|
muldup->next = new; |
411 |
|
|
} |
412 |
|
|
for (dlp = duplist; dlp != muldup; dlp = dlp->next) |
413 |
|
|
if (dlp->dup == blkno) |
414 |
|
|
break; |
415 |
|
|
if (dlp == muldup && dlp->dup != blkno) |
416 |
|
|
muldup = new; |
417 |
|
|
} |
418 |
|
|
/* |
419 |
|
|
* count the number of blocks found in id_entryno |
420 |
|
|
*/ |
421 |
|
8 |
idesc->id_entryno++; |
422 |
|
|
} |
423 |
|
8 |
return (res); |
424 |
|
8 |
} |