inode.c revision 101037
1/*
2 * Copyright (c) 1980, 1986, 1993
3 *	The Regents of the University of California.  All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 *    must display the following acknowledgement:
15 *	This product includes software developed by the University of
16 *	California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 *    may be used to endorse or promote products derived from this software
19 *    without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34#ifndef lint
35#if 0
36static const char sccsid[] = "@(#)inode.c	8.8 (Berkeley) 4/28/95";
37#endif
38static const char rcsid[] =
39  "$FreeBSD: head/sbin/fsck_ffs/inode.c 101037 2002-07-31 12:01:14Z mux $";
40#endif /* not lint */
41
42#include <sys/param.h>
43#include <sys/stdint.h>
44#include <sys/time.h>
45#include <sys/sysctl.h>
46
47#include <ufs/ufs/dinode.h>
48#include <ufs/ufs/dir.h>
49#include <ufs/ffs/fs.h>
50
51#include <err.h>
52#include <pwd.h>
53#include <string.h>
54
55#include "fsck.h"
56
57static ino_t startinum;
58
59static int iblock(struct inodesc *, long ilevel, off_t isize);
60
61int
62ckinode(union dinode *dp, struct inodesc *idesc)
63{
64	off_t remsize, sizepb;
65	int i, offset, ret;
66	union dinode dino;
67	ufs2_daddr_t ndb;
68	mode_t mode;
69	char pathbuf[MAXPATHLEN + 1];
70
71	if (idesc->id_fix != IGNORE)
72		idesc->id_fix = DONTKNOW;
73	idesc->id_lbn = -1;
74	idesc->id_entryno = 0;
75	idesc->id_filesize = DIP(dp, di_size);
76	mode = DIP(dp, di_mode) & IFMT;
77	if (mode == IFBLK || mode == IFCHR || (mode == IFLNK &&
78	    DIP(dp, di_size) < (unsigned)sblock.fs_maxsymlinklen))
79		return (KEEPON);
80	if (sblock.fs_magic == FS_UFS1_MAGIC)
81		dino.dp1 = dp->dp1;
82	else
83		dino.dp2 = dp->dp2;
84	ndb = howmany(DIP(&dino, di_size), sblock.fs_bsize);
85	for (i = 0; i < NDADDR; i++) {
86		idesc->id_lbn++;
87		if (--ndb == 0 &&
88		    (offset = blkoff(&sblock, DIP(&dino, di_size))) != 0)
89			idesc->id_numfrags =
90				numfrags(&sblock, fragroundup(&sblock, offset));
91		else
92			idesc->id_numfrags = sblock.fs_frag;
93		if (DIP(&dino, di_db[i]) == 0) {
94			if (idesc->id_type == DATA && ndb >= 0) {
95				/* An empty block in a directory XXX */
96				getpathname(pathbuf, idesc->id_number,
97						idesc->id_number);
98                        	pfatal("DIRECTORY %s: CONTAINS EMPTY BLOCKS",
99					pathbuf);
100                        	if (reply("ADJUST LENGTH") == 1) {
101					dp = ginode(idesc->id_number);
102                                	DIP(dp, di_size) = i * sblock.fs_bsize;
103					printf(
104					    "YOU MUST RERUN FSCK AFTERWARDS\n");
105					rerun = 1;
106                                	inodirty();
107
108                        	}
109			}
110			continue;
111		}
112		idesc->id_blkno = DIP(&dino, di_db[i]);
113		if (idesc->id_type != DATA)
114			ret = (*idesc->id_func)(idesc);
115		else
116			ret = dirscan(idesc);
117		if (ret & STOP)
118			return (ret);
119	}
120	idesc->id_numfrags = sblock.fs_frag;
121	remsize = DIP(&dino, di_size) - sblock.fs_bsize * NDADDR;
122	sizepb = sblock.fs_bsize;
123	for (i = 0; i < NIADDR; i++) {
124		sizepb *= NINDIR(&sblock);
125		if (DIP(&dino, di_ib[i])) {
126			idesc->id_blkno = DIP(&dino, di_ib[i]);
127			ret = iblock(idesc, i + 1, remsize);
128			if (ret & STOP)
129				return (ret);
130		} else {
131			idesc->id_lbn += sizepb / sblock.fs_bsize;
132			if (idesc->id_type == DATA && remsize > 0) {
133				/* An empty block in a directory XXX */
134				getpathname(pathbuf, idesc->id_number,
135						idesc->id_number);
136                        	pfatal("DIRECTORY %s: CONTAINS EMPTY BLOCKS",
137					pathbuf);
138                        	if (reply("ADJUST LENGTH") == 1) {
139					dp = ginode(idesc->id_number);
140                                	DIP(dp, di_size) -= remsize;
141					remsize = 0;
142					printf(
143					    "YOU MUST RERUN FSCK AFTERWARDS\n");
144					rerun = 1;
145                                	inodirty();
146					break;
147                        	}
148			}
149		}
150		remsize -= sizepb;
151	}
152	return (KEEPON);
153}
154
155static int
156iblock(struct inodesc *idesc, long ilevel, off_t isize)
157{
158	struct bufarea *bp;
159	int i, n, (*func)(struct inodesc *), nif;
160	off_t sizepb;
161	char buf[BUFSIZ];
162	char pathbuf[MAXPATHLEN + 1];
163	union dinode *dp;
164
165	if (idesc->id_type != DATA) {
166		func = idesc->id_func;
167		if (((n = (*func)(idesc)) & KEEPON) == 0)
168			return (n);
169	} else
170		func = dirscan;
171	if (chkrange(idesc->id_blkno, idesc->id_numfrags))
172		return (SKIP);
173	bp = getdatablk(idesc->id_blkno, sblock.fs_bsize);
174	ilevel--;
175	for (sizepb = sblock.fs_bsize, i = 0; i < ilevel; i++)
176		sizepb *= NINDIR(&sblock);
177	if (howmany(isize, sizepb) > NINDIR(&sblock))
178		nif = NINDIR(&sblock);
179	else
180		nif = howmany(isize, sizepb);
181	if (idesc->id_func == pass1check && nif < NINDIR(&sblock)) {
182		for (i = nif; i < NINDIR(&sblock); i++) {
183			if (IBLK(bp, i) == 0)
184				continue;
185			(void)sprintf(buf, "PARTIALLY TRUNCATED INODE I=%lu",
186			    (u_long)idesc->id_number);
187			if (preen) {
188				pfatal("%s", buf);
189			} else if (dofix(idesc, buf)) {
190				IBLK(bp, i) = 0;
191				dirty(bp);
192			}
193		}
194		flush(fswritefd, bp);
195	}
196	for (i = 0; i < nif; i++) {
197		if (ilevel == 0)
198			idesc->id_lbn++;
199		if (IBLK(bp, i)) {
200			idesc->id_blkno = IBLK(bp, i);
201			if (ilevel == 0)
202				n = (*func)(idesc);
203			else
204				n = iblock(idesc, ilevel, isize);
205			if (n & STOP) {
206				bp->b_flags &= ~B_INUSE;
207				return (n);
208			}
209		} else {
210			if (idesc->id_type == DATA && isize > 0) {
211				/* An empty block in a directory XXX */
212				getpathname(pathbuf, idesc->id_number,
213						idesc->id_number);
214                        	pfatal("DIRECTORY %s: CONTAINS EMPTY BLOCKS",
215					pathbuf);
216                        	if (reply("ADJUST LENGTH") == 1) {
217					dp = ginode(idesc->id_number);
218                                	DIP(dp, di_size) -= isize;
219					isize = 0;
220					printf(
221					    "YOU MUST RERUN FSCK AFTERWARDS\n");
222					rerun = 1;
223                                	inodirty();
224					bp->b_flags &= ~B_INUSE;
225					return(STOP);
226                        	}
227			}
228		}
229		isize -= sizepb;
230	}
231	bp->b_flags &= ~B_INUSE;
232	return (KEEPON);
233}
234
235/*
236 * Check that a block in a legal block number.
237 * Return 0 if in range, 1 if out of range.
238 */
239int
240chkrange(ufs2_daddr_t blk, int cnt)
241{
242	int c;
243
244	if (cnt <= 0 || blk <= 0 || blk > maxfsblock ||
245	    cnt - 1 > maxfsblock - blk)
246		return (1);
247	if (cnt > sblock.fs_frag ||
248	    fragnum(&sblock, blk) + cnt > sblock.fs_frag) {
249		if (debug)
250			printf("bad size: blk %ld, offset %i, size %d\n",
251			    (long)blk, (int)fragnum(&sblock, blk), cnt);
252		return (1);
253	}
254	c = dtog(&sblock, blk);
255	if (blk < cgdmin(&sblock, c)) {
256		if ((blk + cnt) > cgsblock(&sblock, c)) {
257			if (debug) {
258				printf("blk %ld < cgdmin %ld;",
259				    (long)blk, (long)cgdmin(&sblock, c));
260				printf(" blk + cnt %ld > cgsbase %ld\n",
261				    (long)(blk + cnt),
262				    (long)cgsblock(&sblock, c));
263			}
264			return (1);
265		}
266	} else {
267		if ((blk + cnt) > cgbase(&sblock, c+1)) {
268			if (debug)  {
269				printf("blk %ld >= cgdmin %ld;",
270				    (long)blk, (long)cgdmin(&sblock, c));
271				printf(" blk + cnt %ld > sblock.fs_fpg %ld\n",
272				    (long)(blk + cnt), (long)sblock.fs_fpg);
273			}
274			return (1);
275		}
276	}
277	return (0);
278}
279
280/*
281 * General purpose interface for reading inodes.
282 */
283union dinode *
284ginode(ino_t inumber)
285{
286	ufs2_daddr_t iblk;
287
288	if (inumber < ROOTINO || inumber > maxino)
289		errx(EEXIT, "bad inode number %d to ginode", inumber);
290	if (startinum == 0 ||
291	    inumber < startinum || inumber >= startinum + INOPB(&sblock)) {
292		iblk = ino_to_fsba(&sblock, inumber);
293		if (pbp != 0)
294			pbp->b_flags &= ~B_INUSE;
295		pbp = getdatablk(iblk, sblock.fs_bsize);
296		startinum = (inumber / INOPB(&sblock)) * INOPB(&sblock);
297	}
298	if (sblock.fs_magic == FS_UFS1_MAGIC)
299		return ((union dinode *)
300		    &pbp->b_un.b_dinode1[inumber % INOPB(&sblock)]);
301	return ((union dinode *)&pbp->b_un.b_dinode2[inumber % INOPB(&sblock)]);
302}
303
304/*
305 * Special purpose version of ginode used to optimize first pass
306 * over all the inodes in numerical order.
307 */
308static ino_t nextino, lastinum, lastvalidinum;
309static long readcnt, readpercg, fullcnt, inobufsize, partialcnt, partialsize;
310static caddr_t inodebuf;
311
312union dinode *
313getnextinode(ino_t inumber)
314{
315	long size;
316	ufs2_daddr_t dblk;
317	union dinode *dp;
318	static caddr_t nextinop;
319
320	if (inumber != nextino++ || inumber > lastvalidinum)
321		errx(EEXIT, "bad inode number %d to nextinode", inumber);
322	if (inumber >= lastinum) {
323		readcnt++;
324		dblk = fsbtodb(&sblock, ino_to_fsba(&sblock, lastinum));
325		if (readcnt % readpercg == 0) {
326			size = partialsize;
327			lastinum += partialcnt;
328		} else {
329			size = inobufsize;
330			lastinum += fullcnt;
331		}
332		/*
333		 * If bread returns an error, it will already have zeroed
334		 * out the buffer, so we do not need to do so here.
335		 */
336		(void)bread(fsreadfd, inodebuf, dblk, size);
337		nextinop = inodebuf;
338	}
339	dp = (union dinode *)nextinop;
340	if (sblock.fs_magic == FS_UFS1_MAGIC)
341		nextinop += sizeof(struct ufs1_dinode);
342	else
343		nextinop += sizeof(struct ufs2_dinode);
344	return (dp);
345}
346
347void
348setinodebuf(ino_t inum)
349{
350
351	if (inum % sblock.fs_ipg != 0)
352		errx(EEXIT, "bad inode number %d to setinodebuf", inum);
353	lastvalidinum = inum + sblock.fs_ipg - 1;
354	startinum = 0;
355	nextino = inum;
356	lastinum = inum;
357	readcnt = 0;
358	if (inodebuf != NULL)
359		return;
360	inobufsize = blkroundup(&sblock, INOBUFSIZE);
361	fullcnt = inobufsize / ((sblock.fs_magic == FS_UFS1_MAGIC) ?
362	    sizeof(struct ufs1_dinode) : sizeof(struct ufs2_dinode));
363	readpercg = sblock.fs_ipg / fullcnt;
364	partialcnt = sblock.fs_ipg % fullcnt;
365	partialsize = partialcnt * ((sblock.fs_magic == FS_UFS1_MAGIC) ?
366	    sizeof(struct ufs1_dinode) : sizeof(struct ufs2_dinode));
367	if (partialcnt != 0) {
368		readpercg++;
369	} else {
370		partialcnt = fullcnt;
371		partialsize = inobufsize;
372	}
373	if ((inodebuf = malloc((unsigned)inobufsize)) == NULL)
374		errx(EEXIT, "cannot allocate space for inode buffer");
375}
376
377void
378freeinodebuf(void)
379{
380
381	if (inodebuf != NULL)
382		free((char *)inodebuf);
383	inodebuf = NULL;
384}
385
386/*
387 * Routines to maintain information about directory inodes.
388 * This is built during the first pass and used during the
389 * second and third passes.
390 *
391 * Enter inodes into the cache.
392 */
393void
394cacheino(union dinode *dp, ino_t inumber)
395{
396	struct inoinfo *inp, **inpp;
397	int i, blks;
398
399	if (howmany(DIP(dp, di_size), sblock.fs_bsize) > NDADDR)
400		blks = NDADDR + NIADDR;
401	else
402		blks = howmany(DIP(dp, di_size), sblock.fs_bsize);
403	inp = (struct inoinfo *)
404		malloc(sizeof(*inp) + (blks - 1) * sizeof(ufs2_daddr_t));
405	if (inp == NULL)
406		errx(EEXIT, "cannot increase directory list");
407	inpp = &inphead[inumber % dirhash];
408	inp->i_nexthash = *inpp;
409	*inpp = inp;
410	inp->i_parent = inumber == ROOTINO ? ROOTINO : (ino_t)0;
411	inp->i_dotdot = (ino_t)0;
412	inp->i_number = inumber;
413	inp->i_isize = DIP(dp, di_size);
414	inp->i_numblks = blks;
415	for (i = 0; i < (blks < NDADDR ? blks : NDADDR); i++)
416		inp->i_blks[i] = DIP(dp, di_db[i]);
417	if (blks > NDADDR)
418		for (i = 0; i < NIADDR; i++)
419			inp->i_blks[NDADDR + i] = DIP(dp, di_ib[i]);
420	if (inplast == listmax) {
421		listmax += 100;
422		inpsort = (struct inoinfo **)realloc((char *)inpsort,
423		    (unsigned)listmax * sizeof(struct inoinfo *));
424		if (inpsort == NULL)
425			errx(EEXIT, "cannot increase directory list");
426	}
427	inpsort[inplast++] = inp;
428}
429
430/*
431 * Look up an inode cache structure.
432 */
433struct inoinfo *
434getinoinfo(ino_t inumber)
435{
436	struct inoinfo *inp;
437
438	for (inp = inphead[inumber % dirhash]; inp; inp = inp->i_nexthash) {
439		if (inp->i_number != inumber)
440			continue;
441		return (inp);
442	}
443	errx(EEXIT, "cannot find inode %d", inumber);
444	return ((struct inoinfo *)0);
445}
446
447/*
448 * Clean up all the inode cache structure.
449 */
450void
451inocleanup(void)
452{
453	struct inoinfo **inpp;
454
455	if (inphead == NULL)
456		return;
457	for (inpp = &inpsort[inplast - 1]; inpp >= inpsort; inpp--)
458		free((char *)(*inpp));
459	free((char *)inphead);
460	free((char *)inpsort);
461	inphead = inpsort = NULL;
462}
463
464void
465inodirty(void)
466{
467
468	dirty(pbp);
469}
470
471void
472clri(struct inodesc *idesc, const char *type, int flag)
473{
474	union dinode *dp;
475
476	dp = ginode(idesc->id_number);
477	if (flag == 1) {
478		pwarn("%s %s", type,
479		    (DIP(dp, di_mode) & IFMT) == IFDIR ? "DIR" : "FILE");
480		pinode(idesc->id_number);
481	}
482	if (preen || reply("CLEAR") == 1) {
483		if (preen)
484			printf(" (CLEARED)\n");
485		n_files--;
486		if (bkgrdflag == 0) {
487			(void)ckinode(dp, idesc);
488			inoinfo(idesc->id_number)->ino_state = USTATE;
489			clearinode(dp);
490			inodirty();
491		} else {
492			cmd.value = idesc->id_number;
493			cmd.size = -DIP(dp, di_nlink);
494			if (debug)
495				printf("adjrefcnt ino %ld amt %lld\n",
496				    (long)cmd.value, (long long)cmd.size);
497			if (sysctl(adjrefcnt, MIBSIZE, 0, 0,
498			    &cmd, sizeof cmd) == -1)
499				rwerror("ADJUST INODE", cmd.value);
500		}
501	}
502}
503
504int
505findname(struct inodesc *idesc)
506{
507	struct direct *dirp = idesc->id_dirp;
508
509	if (dirp->d_ino != idesc->id_parent || idesc->id_entryno < 2) {
510		idesc->id_entryno++;
511		return (KEEPON);
512	}
513	memmove(idesc->id_name, dirp->d_name, (size_t)dirp->d_namlen + 1);
514	return (STOP|FOUND);
515}
516
517int
518findino(struct inodesc *idesc)
519{
520	struct direct *dirp = idesc->id_dirp;
521
522	if (dirp->d_ino == 0)
523		return (KEEPON);
524	if (strcmp(dirp->d_name, idesc->id_name) == 0 &&
525	    dirp->d_ino >= ROOTINO && dirp->d_ino <= maxino) {
526		idesc->id_parent = dirp->d_ino;
527		return (STOP|FOUND);
528	}
529	return (KEEPON);
530}
531
532int
533clearentry(struct inodesc *idesc)
534{
535	struct direct *dirp = idesc->id_dirp;
536
537	if (dirp->d_ino != idesc->id_parent || idesc->id_entryno < 2) {
538		idesc->id_entryno++;
539		return (KEEPON);
540	}
541	dirp->d_ino = 0;
542	return (STOP|FOUND|ALTERED);
543}
544
545void
546pinode(ino_t ino)
547{
548	union dinode *dp;
549	char *p;
550	struct passwd *pw;
551	time_t t;
552
553	printf(" I=%lu ", (u_long)ino);
554	if (ino < ROOTINO || ino > maxino)
555		return;
556	dp = ginode(ino);
557	printf(" OWNER=");
558	if ((pw = getpwuid((int)DIP(dp, di_uid))) != 0)
559		printf("%s ", pw->pw_name);
560	else
561		printf("%u ", (unsigned)DIP(dp, di_uid));
562	printf("MODE=%o\n", DIP(dp, di_mode));
563	if (preen)
564		printf("%s: ", cdevname);
565	printf("SIZE=%ju ", (uintmax_t)DIP(dp, di_size));
566	t = DIP(dp, di_mtime);
567	p = ctime(&t);
568	printf("MTIME=%12.12s %4.4s ", &p[4], &p[20]);
569}
570
571void
572blkerror(ino_t ino, const char *type, ufs2_daddr_t blk)
573{
574
575	pfatal("%jd %s I=%ju", (intmax_t)blk, type, (uintmax_t)ino);
576	printf("\n");
577	switch (inoinfo(ino)->ino_state) {
578
579	case FSTATE:
580		inoinfo(ino)->ino_state = FCLEAR;
581		return;
582
583	case DSTATE:
584		inoinfo(ino)->ino_state = DCLEAR;
585		return;
586
587	case FCLEAR:
588	case DCLEAR:
589		return;
590
591	default:
592		errx(EEXIT, "BAD STATE %d TO BLKERR", inoinfo(ino)->ino_state);
593		/* NOTREACHED */
594	}
595}
596
597/*
598 * allocate an unused inode
599 */
600ino_t
601allocino(ino_t request, int type)
602{
603	ino_t ino;
604	union dinode *dp;
605	struct cg *cgp = &cgrp;
606	int cg;
607
608	if (request == 0)
609		request = ROOTINO;
610	else if (inoinfo(request)->ino_state != USTATE)
611		return (0);
612	for (ino = request; ino < maxino; ino++)
613		if (inoinfo(ino)->ino_state == USTATE)
614			break;
615	if (ino == maxino)
616		return (0);
617	cg = ino_to_cg(&sblock, ino);
618	getblk(&cgblk, cgtod(&sblock, cg), sblock.fs_cgsize);
619	if (!cg_chkmagic(cgp))
620		pfatal("CG %d: BAD MAGIC NUMBER\n", cg);
621	setbit(cg_inosused(cgp), ino % sblock.fs_ipg);
622	cgp->cg_cs.cs_nifree--;
623	switch (type & IFMT) {
624	case IFDIR:
625		inoinfo(ino)->ino_state = DSTATE;
626		cgp->cg_cs.cs_ndir++;
627		break;
628	case IFREG:
629	case IFLNK:
630		inoinfo(ino)->ino_state = FSTATE;
631		break;
632	default:
633		return (0);
634	}
635	cgdirty();
636	dp = ginode(ino);
637	DIP(dp, di_db[0]) = allocblk((long)1);
638	if (DIP(dp, di_db[0]) == 0) {
639		inoinfo(ino)->ino_state = USTATE;
640		return (0);
641	}
642	DIP(dp, di_mode) = type;
643	DIP(dp, di_flags) = 0;
644	DIP(dp, di_atime) = time(NULL);
645	DIP(dp, di_mtime) = DIP(dp, di_ctime) = DIP(dp, di_atime);
646	DIP(dp, di_mtimensec) = 0;
647	DIP(dp, di_ctimensec) = 0;
648	DIP(dp, di_atimensec) = 0;
649	DIP(dp, di_size) = sblock.fs_fsize;
650	DIP(dp, di_blocks) = btodb(sblock.fs_fsize);
651	n_files++;
652	inodirty();
653	inoinfo(ino)->ino_type = IFTODT(type);
654	return (ino);
655}
656
657/*
658 * deallocate an inode
659 */
660void
661freeino(ino_t ino)
662{
663	struct inodesc idesc;
664	union dinode *dp;
665
666	memset(&idesc, 0, sizeof(struct inodesc));
667	idesc.id_type = ADDR;
668	idesc.id_func = pass4check;
669	idesc.id_number = ino;
670	dp = ginode(ino);
671	(void)ckinode(dp, &idesc);
672	clearinode(dp);
673	inodirty();
674	inoinfo(ino)->ino_state = USTATE;
675	n_files--;
676}
677