1 /*
2  *  ADF Library. (C) 1997-2002 Laurent Clevy
3  *
4  *  adf_salv.c
5  *
6  *  $Id$
7  *
8  * undelete and salvage code : EXPERIMENTAL !
9  *
10  *  This file is part of ADFLib.
11  *
12  *  ADFLib is free software; you can redistribute it and/or modify
13  *  it under the terms of the GNU General Public License as published by
14  *  the Free Software Foundation; either version 2 of the License, or
15  *  (at your option) any later version.
16  *
17  *  ADFLib is distributed in the hope that it will be useful,
18  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
19  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  *  GNU General Public License for more details.
21  *
22  *  You should have received a copy of the GNU General Public License
23  *  along with Foobar; if not, write to the Free Software
24  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
25  *
26  */
27 
28 #include<string.h>
29 #include<stdlib.h>
30 
31 #include "adf_salv.h"
32 #include "adf_bitm.h"
33 #include "adf_util.h"
34 #include "adf_disk.h"
35 #include "adf_dir.h"
36 #include "adf_file.h"
37 #include "adf_cache.h"
38 
39 extern struct Env adfEnv;
40 
41 /*
42  * adfFreeGenBlock
43  *
44  */
adfFreeGenBlock(struct GenBlock * block)45 void adfFreeGenBlock(struct GenBlock* block)
46 {
47     if (block->name!=NULL)
48         free(block->name);
49 }
50 
51 
52 /*
53  * adfFreeDelList
54  *
55  */
adfFreeDelList(struct List * list)56 void adfFreeDelList(struct List* list)
57 {
58     struct List *cell;
59 
60     cell = list;
61     while(cell!=NULL) {
62         adfFreeGenBlock((struct GenBlock*)cell->content);
63         cell = cell->next;
64     }
65     freeList(list);
66 }
67 
68 
69 /*
70  * adfGetDelEnt
71  *
72  */
adfGetDelEnt(struct Volume * vol)73 struct List* adfGetDelEnt(struct Volume *vol)
74 {
75     struct GenBlock *block;
76     int32_t i;
77     struct List *list, *head;
78     BOOL delEnt;
79 
80     list = head = NULL;
81     block = NULL;
82     delEnt = TRUE;
83     for(i=vol->firstBlock; i<=vol->lastBlock; i++) {
84         if (adfIsBlockFree(vol, i)) {
85             if (delEnt) {
86                 block = (struct GenBlock*)malloc(sizeof(struct GenBlock));
87                 if (!block) return NULL;
88 /*printf("%p\n",block);*/
89             }
90 
91             adfReadGenBlock(vol, i, block);
92 
93             delEnt = (block->type==T_HEADER
94                 && (block->secType==ST_DIR || block->secType==ST_FILE) );
95 
96             if (delEnt) {
97                 if (head==NULL)
98                     list = head = newCell(NULL, (void*)block);
99                 else
100                     list = newCell(list, (void*)block);
101             }
102         }
103     }
104 
105     if (block!=NULL && list!=NULL && block!=list->content) {
106         free(block);
107 /*        printf("%p\n",block);*/
108     }
109     return head;
110 }
111 
112 
113 /*
114  * adfReadGenBlock
115  *
116  */
adfReadGenBlock(struct Volume * vol,SECTNUM nSect,struct GenBlock * block)117 RETCODE adfReadGenBlock(struct Volume *vol, SECTNUM nSect, struct GenBlock *block)
118 {
119 	uint8_t buf[LOGICAL_BLOCK_SIZE];
120     int len;
121     char name[MAXNAMELEN+1];
122 
123 	if (adfReadBlock(vol, nSect, buf)!=RC_OK)
124 		return RC_ERROR;
125 
126     block->type =(int) swapLong(buf);
127     block->secType =(int) swapLong(buf+vol->blockSize-4);
128     block->sect = nSect;
129     block->name = NULL;
130 
131     if (block->type==T_HEADER) {
132         switch(block->secType) {
133         case ST_FILE:
134         case ST_DIR:
135         case ST_LFILE:
136         case ST_LDIR:
137             len = min(MAXNAMELEN, buf[vol->blockSize-80]);
138             strncpy(name, (char*)buf+vol->blockSize-79, len);
139             name[len] = '\0';
140             block->name = strdup(name);
141             block->parent = swapLong(buf+vol->blockSize-12);
142             break;
143         case ST_ROOT:
144             break;
145         default:
146             ;
147         }
148     }
149     return RC_OK;
150 }
151 
152 
153 /*
154  * adfCheckParent
155  *
156  */
adfCheckParent(struct Volume * vol,SECTNUM pSect)157 RETCODE adfCheckParent(struct Volume* vol, SECTNUM pSect)
158 {
159     struct GenBlock block;
160 
161     if (adfIsBlockFree(vol, pSect)) {
162         (*adfEnv.wFct)("adfCheckParent : parent doesn't exists");
163         return RC_ERROR;
164     }
165 
166     /* verify if parent is a DIR or ROOT */
167     adfReadGenBlock(vol, pSect, &block);
168     if ( block.type!=T_HEADER
169         || (block.secType!=ST_DIR && block.secType!=ST_ROOT) ) {
170         (*adfEnv.wFct)("adfCheckParent : parent secType is incorrect");
171         return RC_ERROR;
172     }
173 
174     return RC_OK;
175 }
176 
177 
178 /*
179  * adfUndelDir
180  *
181  */
adfUndelDir(struct Volume * vol,SECTNUM pSect,SECTNUM nSect,struct bDirBlock * entry)182 RETCODE adfUndelDir(struct Volume* vol, SECTNUM pSect, SECTNUM nSect,
183     struct bDirBlock* entry)
184 {
185     RETCODE rc;
186     struct bEntryBlock parent;
187     char name[MAXNAMELEN+1];
188 
189     /* check if the given parent sector pointer seems OK */
190     if ( (rc=adfCheckParent(vol,pSect)) != RC_OK)
191         return rc;
192 
193     if (pSect!=entry->parent) {
194         (*adfEnv.wFct)("adfUndelDir : the given parent sector isn't the entry parent");
195         return RC_ERROR;
196     }
197 
198     if (!adfIsBlockFree(vol, entry->headerKey))
199         return RC_ERROR;
200     if (isDIRCACHE(vol->dosType) && !adfIsBlockFree(vol,entry->extension))
201         return RC_ERROR;
202 
203     if (adfReadEntryBlock(vol, pSect, &parent)!=RC_OK)
204 		return RC_ERROR;
205 
206     strncpy(name, entry->dirName, entry->nameLen);
207     name[(int)entry->nameLen] = '\0';
208     /* insert the entry in the parent hashTable, with the headerKey sector pointer */
209     adfSetBlockUsed(vol,entry->headerKey);
210     adfCreateEntry(vol, &parent, name, entry->headerKey);
211 
212     if (isDIRCACHE(vol->dosType)) {
213         adfAddInCache(vol, &parent, (struct bEntryBlock *)entry);
214         adfSetBlockUsed(vol,entry->extension);
215     }
216 
217     adfUpdateBitmap(vol);
218 
219     return RC_OK;
220 }
221 
222 
223 /*
224  * adfUndelFile
225  *
226  */
adfUndelFile(struct Volume * vol,SECTNUM pSect,SECTNUM nSect,struct bFileHeaderBlock * entry)227 RETCODE adfUndelFile(struct Volume* vol, SECTNUM pSect, SECTNUM nSect, struct bFileHeaderBlock* entry)
228 {
229     int32_t i;
230     char name[MAXNAMELEN+1];
231     struct bEntryBlock parent;
232     RETCODE rc;
233     struct FileBlocks fileBlocks;
234 
235     /* check if the given parent sector pointer seems OK */
236     if ( (rc=adfCheckParent(vol,pSect)) != RC_OK)
237         return rc;
238 
239     if (pSect!=entry->parent) {
240         (*adfEnv.wFct)("adfUndelFile : the given parent sector isn't the entry parent");
241         return RC_ERROR;
242     }
243 
244     adfGetFileBlocks(vol, entry, &fileBlocks);
245 
246     for(i=0; i<fileBlocks.nbData; i++)
247         if ( !adfIsBlockFree(vol,fileBlocks.data[i]) )
248             return RC_ERROR;
249         else
250             adfSetBlockUsed(vol, fileBlocks.data[i]);
251     for(i=0; i<fileBlocks.nbExtens; i++)
252         if ( !adfIsBlockFree(vol,fileBlocks.extens[i]) )
253             return RC_ERROR;
254         else
255             adfSetBlockUsed(vol, fileBlocks.extens[i]);
256 
257     free(fileBlocks.data);
258     free(fileBlocks.extens);
259 
260     if (adfReadEntryBlock(vol, pSect, &parent)!=RC_OK)
261 		return RC_ERROR;
262 
263     strncpy(name, entry->fileName, entry->nameLen);
264     name[(int)entry->nameLen] = '\0';
265     /* insert the entry in the parent hashTable, with the headerKey sector pointer */
266     adfCreateEntry(vol, &parent, name, entry->headerKey);
267 
268     if (isDIRCACHE(vol->dosType))
269         adfAddInCache(vol, &parent, (struct bEntryBlock *)entry);
270 
271     adfUpdateBitmap(vol);
272 
273     return RC_OK;
274 }
275 
276 
277 /*
278  * adfUndelEntry
279  *
280  */
adfUndelEntry(struct Volume * vol,SECTNUM parent,SECTNUM nSect)281 RETCODE adfUndelEntry(struct Volume* vol, SECTNUM parent, SECTNUM nSect)
282 {
283     struct bEntryBlock entry;
284 
285     adfReadEntryBlock(vol,nSect,&entry);
286 
287     switch(entry.secType) {
288     case ST_FILE:
289         adfUndelFile(vol, parent, nSect, (struct bFileHeaderBlock*)&entry);
290         break;
291     case ST_DIR:
292         adfUndelDir(vol, parent, nSect, (struct bDirBlock*)&entry);
293         break;
294     default:
295         ;
296     }
297 
298     return RC_OK;
299 }
300 
301 
302 /*
303  * adfCheckFile
304  *
305  */
adfCheckFile(struct Volume * vol,SECTNUM nSect,struct bFileHeaderBlock * file,int level)306 RETCODE adfCheckFile(struct Volume* vol, SECTNUM nSect,
307     struct bFileHeaderBlock* file, int level)
308 {
309     struct bFileExtBlock extBlock;
310     struct bOFSDataBlock dataBlock;
311     struct FileBlocks fileBlocks;
312     int n;
313 
314     adfGetFileBlocks(vol,file,&fileBlocks);
315 /*printf("data %ld ext %ld\n",fileBlocks.nbData,fileBlocks.nbExtens);*/
316     if (isOFS(vol->dosType)) {
317         /* checks OFS datablocks */
318         for(n=0; n<fileBlocks.nbData; n++) {
319 /*printf("%ld\n",fileBlocks.data[n]);*/
320             adfReadDataBlock(vol,fileBlocks.data[n],&dataBlock);
321             if (dataBlock.headerKey!=fileBlocks.header)
322                 (*adfEnv.wFct)("adfCheckFile : headerKey incorrect");
323             if (dataBlock.seqNum!=n+1)
324                 (*adfEnv.wFct)("adfCheckFile : seqNum incorrect");
325             if (n<fileBlocks.nbData-1) {
326                 if (dataBlock.nextData!=fileBlocks.data[n+1])
327                     (*adfEnv.wFct)("adfCheckFile : nextData incorrect");
328                 if (dataBlock.dataSize!=vol->datablockSize)
329                     (*adfEnv.wFct)("adfCheckFile : dataSize incorrect");
330             }
331             else { /* last datablock */
332                 if (dataBlock.nextData!=0)
333                     (*adfEnv.wFct)("adfCheckFile : nextData incorrect");
334             }
335         }
336     }
337     for(n=0; n<fileBlocks.nbExtens; n++) {
338         adfReadFileExtBlock(vol,fileBlocks.extens[n],&extBlock);
339         if (extBlock.parent!=file->headerKey)
340             (*adfEnv.wFct)("adfCheckFile : extBlock parent incorrect");
341         if (n<fileBlocks.nbExtens-1) {
342             if (extBlock.extension!=fileBlocks.extens[n+1])
343                 (*adfEnv.wFct)("adfCheckFile : nextData incorrect");
344         }
345         else
346             if (extBlock.extension!=0)
347                 (*adfEnv.wFct)("adfCheckFile : nextData incorrect");
348     }
349 
350     free(fileBlocks.data);
351     free(fileBlocks.extens);
352 
353     return RC_OK;
354 }
355 
356 
357 /*
358  * adfCheckDir
359  *
360  */
adfCheckDir(struct Volume * vol,SECTNUM nSect,struct bDirBlock * dir,int level)361 RETCODE adfCheckDir(struct Volume* vol, SECTNUM nSect, struct bDirBlock* dir,
362     int level)
363 {
364 
365 
366 
367 
368     return RC_OK;
369 }
370 
371 
372 /*
373  * adfCheckEntry
374  *
375  */
adfCheckEntry(struct Volume * vol,SECTNUM nSect,int level)376 RETCODE adfCheckEntry(struct Volume* vol, SECTNUM nSect, int level)
377 {
378     struct bEntryBlock entry;
379     RETCODE rc;
380 
381     adfReadEntryBlock(vol,nSect,&entry);
382 
383     switch(entry.secType) {
384     case ST_FILE:
385         rc = adfCheckFile(vol, nSect, (struct bFileHeaderBlock*)&entry, level);
386         break;
387     case ST_DIR:
388         rc = adfCheckDir(vol, nSect, (struct bDirBlock*)&entry, level);
389         break;
390     default:
391 /*        printf("adfCheckEntry : not supported\n");*/					/* BV */
392         rc = RC_ERROR;
393     }
394 
395     return rc;
396 }
397 
398 
399 /*#############################################################################*/
400