diff options
Diffstat (limited to 'src/lib/hd24fs.cpp')
-rwxr-xr-x | src/lib/hd24fs.cpp | 3002 |
1 files changed, 3002 insertions, 0 deletions
diff --git a/src/lib/hd24fs.cpp b/src/lib/hd24fs.cpp new file mode 100755 index 0000000..5c6b3fc --- /dev/null +++ b/src/lib/hd24fs.cpp | |||
@@ -0,0 +1,3002 @@ | |||
1 | #define ALLOC_SECTORS_PER_SONG 5 | ||
2 | #define SONG_SECTORS_PER_SONG 2 | ||
3 | #define TOTAL_SECTORS_PER_SONG (ALLOC_SECTORS_PER_SONG+SONG_SECTORS_PER_SONG) | ||
4 | #ifdef DARWIN | ||
5 | #define creat64 creat | ||
6 | #endif | ||
7 | #define HD24FSDEBUG 0 /* generic hd24fs debugging */ | ||
8 | #define HD24FSDEBUG_QUICKFORMAT 0 /* debugging for calculation of # of free clusters */ | ||
9 | #define HD24FSDEBUG_WRITE 0 /* output debugging messages on disk writes */ | ||
10 | #define HD24FSDEBUG_BITSET 0 /* output debugging messages on disk writes */ | ||
11 | #define HD24FSDEBUG_COMMIT 0 /* output debugging messages on disk writes */ | ||
12 | #define HD24FSDEBUG_DEVSCAN 0 /* output debugging messages for device scan */ | ||
13 | #include "hd24fs.h" | ||
14 | #include <string> | ||
15 | #include <sys/types.h> | ||
16 | #include <sys/stat.h> | ||
17 | #include <fcntl.h> | ||
18 | #ifndef WINDOWS | ||
19 | #include <unistd.h> | ||
20 | #endif | ||
21 | #define RESULT_SUCCESS 0 | ||
22 | #define RESULT_FAIL 1 | ||
23 | #include <stdio.h> | ||
24 | #include <stdlib.h> | ||
25 | #include <iostream> | ||
26 | #include <fstream> | ||
27 | #include <math.h> | ||
28 | #include "convertlib.h" | ||
29 | #include "memutils.h" | ||
30 | |||
31 | #include <hd24devicenamegenerator.h> | ||
32 | #define _LARGE_FILES | ||
33 | #define _FILE_OFFSET_BITS 64 | ||
34 | #define FILE_OFFSET_BITS 64 | ||
35 | #define LARGE_FILES | ||
36 | #define LARGEFILE64_SOURCE | ||
37 | #define SECTORSIZE 512 | ||
38 | #ifdef DARWIN | ||
39 | #define open64 open | ||
40 | #define lseek64 lseek | ||
41 | #define pread64 pread | ||
42 | #define pwrite64 pwrite | ||
43 | #endif | ||
44 | #define FSINFO_VERSION_MAJOR 0x8 | ||
45 | #define FSINFO_VERSION_MINOR 0x9 | ||
46 | #define FSINFO_BLOCKSIZE_IN_SECTORS 0x10 | ||
47 | #define FSINFO_AUDIOBLOCKS_PER_CLUSTER 0x14 | ||
48 | #define FSINFO_STARTSECTOR_DRIVEUSAGE 0x38 | ||
49 | #define FSINFO_NUMSECTORS_DRIVEUSAGE 0x3c | ||
50 | #define FSINFO_FREE_CLUSTERS_ON_DISK 0x44 | ||
51 | #define FSINFO_FIRST_PROJECT_SECTOR 0x48 | ||
52 | #define FSINFO_SECTORS_PER_PROJECT 0x4C | ||
53 | #define FSINFO_MAXPROJECTS 0x50 | ||
54 | #define FSINFO_MAXSONGSPERPROJECT 0x54 | ||
55 | #define FSINFO_FIRST_SONG_SECTOR 0x58 | ||
56 | #define FSINFO_SECTORS_IN_SONGENTRY 0x5C | ||
57 | #define FSINFO_SECTORS_IN_SONGALLOC 0x60 | ||
58 | #define FSINFO_SECTORS_PER_SONG 0x64 | ||
59 | #define FSINFO_CURRENT_SONGS_ON_DISK 0x68 | ||
60 | #define FSINFO_ALLOCATABLE_SECTORCOUNT 0x80 | ||
61 | #define FSINFO_LAST_SECTOR 0x84 | ||
62 | #define FSINFO_DATAAREA 0x7c | ||
63 | |||
64 | #define DRIVEINFO_VOLUME 0x1b8 | ||
65 | #define DRIVEINFO_VOLUME_8 0x00 | ||
66 | #define DRIVEINFO_PROJECTCOUNT 0x0c | ||
67 | #define DRIVEINFO_LASTPROJ 0x10 | ||
68 | #define DRIVEINFO_LASTPROJECT 0x10 | ||
69 | #define DRIVEINFO_PROJECTLIST 0x20 | ||
70 | |||
71 | #include "hd24project.cpp" | ||
72 | #include "hd24song.cpp" | ||
73 | #if defined(LINUX) || defined(DARWIN) | ||
74 | const int hd24fs::MODE_RDONLY=O_RDONLY; | ||
75 | const int hd24fs::MODE_RDWR=O_RDWR; | ||
76 | #endif | ||
77 | #ifdef WINDOWS | ||
78 | #include <shellapi.h> | ||
79 | const int hd24fs::MODE_RDONLY=GENERIC_READ; | ||
80 | const int hd24fs::MODE_RDWR=GENERIC_READ|GENERIC_WRITE; | ||
81 | #define popen _popen | ||
82 | #define pclose _pclose | ||
83 | #endif | ||
84 | |||
85 | const int hd24fs::TRANSPORTSTATUS_STOP =0; | ||
86 | const int hd24fs::TRANSPORTSTATUS_REC =1; | ||
87 | const int hd24fs::TRANSPORTSTATUS_PLAY =2; | ||
88 | |||
89 | void dumpsector(const char* buffer) | ||
90 | { | ||
91 | for (int i=0;i<512;i+=16) { | ||
92 | string* dummy=Convert::int32tohex(i); | ||
93 | cout << *dummy << " "; | ||
94 | delete dummy; dummy=NULL; | ||
95 | for (int j=0;j<16;j++) { | ||
96 | string* dummy= Convert::byte2hex(buffer[i+j]); | ||
97 | cout << *dummy; | ||
98 | if (j==7) { | ||
99 | cout << "-" ; | ||
100 | } else { | ||
101 | cout << " " ; | ||
102 | } | ||
103 | delete dummy; dummy=NULL; | ||
104 | } | ||
105 | cout << " "; | ||
106 | for (int j=0;j<16;j++) { | ||
107 | cout << Convert::safebyte(buffer[i+j]); | ||
108 | } | ||
109 | cout << "" << endl; | ||
110 | } | ||
111 | } | ||
112 | |||
113 | __uint32 hd24fs::songentry2sector(__uint32 songentry) | ||
114 | { | ||
115 | // Given the possibility to store 99*99 songs, | ||
116 | // converts the song number (0..99*99-1) to | ||
117 | // the sector where the info of that song starts. | ||
118 | // TODO: answer is FSINFO_FIRST_SONG_SECTOR+(FSINFO_SECTORS_PER_SONG*songentry) | ||
119 | // returns 0 when entry number is not legal. | ||
120 | getsector_bootinfo(); | ||
121 | if (sector_boot==NULL) { | ||
122 | // info needed for the calculation is missing. | ||
123 | return 0; | ||
124 | } | ||
125 | __uint32 firstsongsec=Convert::getint32(sector_boot,FSINFO_FIRST_SONG_SECTOR); | ||
126 | __uint32 secspersong=Convert::getint32(sector_boot,FSINFO_SECTORS_PER_SONG); | ||
127 | if (songentry<(99*99)) { | ||
128 | __uint32 secnum=(firstsongsec+(songentry*secspersong)); | ||
129 | return secnum; | ||
130 | } | ||
131 | return 0; // entry number is not legal. | ||
132 | } | ||
133 | |||
134 | __uint32 hd24fs::songsondisk() | ||
135 | { | ||
136 | getsector_bootinfo(); | ||
137 | if (sector_boot==NULL) { | ||
138 | // info needed for the calculation is missing. | ||
139 | return 0; | ||
140 | } | ||
141 | return Convert::getint32(sector_boot,FSINFO_CURRENT_SONGS_ON_DISK); | ||
142 | } | ||
143 | |||
144 | void hd24fs::songsondisk(__uint32 songcount) | ||
145 | { | ||
146 | getsector_bootinfo(); | ||
147 | if (sector_boot==NULL) { | ||
148 | // info needed for the calculation is missing. | ||
149 | return; //cannot update. | ||
150 | } | ||
151 | Convert::setint32(sector_boot,FSINFO_CURRENT_SONGS_ON_DISK,songcount); | ||
152 | } | ||
153 | |||
154 | __uint32 hd24fs::songsector2entry(__uint32 songsector) | ||
155 | { | ||
156 | // given the sector where a song entry starts, | ||
157 | // returns the entry number of that song. | ||
158 | // Entry number typically ranges from 0 | ||
159 | // to (99*99)-1. | ||
160 | // A value 0xffffffff is returned when the | ||
161 | // sector number is not valid. | ||
162 | getsector_bootinfo(); | ||
163 | if (sector_boot==NULL) { | ||
164 | // info needed for the calculation is missing. | ||
165 | return 0xFFFFFFFF; // sector number is not valid. | ||
166 | } | ||
167 | __uint32 firstsongsec=Convert::getint32(sector_boot,FSINFO_FIRST_SONG_SECTOR); | ||
168 | __uint32 secspersong=Convert::getint32(sector_boot,FSINFO_SECTORS_PER_SONG); | ||
169 | __uint32 offset=songsector-firstsongsec; | ||
170 | if ((offset%secspersong) !=0) { | ||
171 | return 0xFFFFFFFF; // sector number is not valid. | ||
172 | } | ||
173 | __uint32 resultentry=(offset/secspersong); | ||
174 | if (resultentry>=(99*99)) return 0xFFFFFFFF; | ||
175 | return resultentry; | ||
176 | } | ||
177 | |||
178 | __uint32 hd24fs::cluster2sector(__uint32 clusternum) | ||
179 | { | ||
180 | getsector_bootinfo(); | ||
181 | if (sector_boot==NULL) { | ||
182 | // unknown cluster size. | ||
183 | return 0; | ||
184 | } | ||
185 | return Convert::getint32(sector_boot,FSINFO_DATAAREA) /* first audio sector */ | ||
186 | +( | ||
187 | Convert::getint32(sector_boot,FSINFO_BLOCKSIZE_IN_SECTORS) | ||
188 | * Convert::getint32(sector_boot,FSINFO_AUDIOBLOCKS_PER_CLUSTER) | ||
189 | * clusternum | ||
190 | ); | ||
191 | } | ||
192 | |||
193 | __uint32 hd24fs::sector2cluster(__uint32 sectornum) | ||
194 | { | ||
195 | getsector_bootinfo(); | ||
196 | if (sector_boot==NULL) { | ||
197 | // unknown cluster size. Return 'undefined' cluster number. | ||
198 | return CLUSTER_UNDEFINED; | ||
199 | } | ||
200 | __uint32 dataarea=Convert::getint32(sector_boot,FSINFO_DATAAREA); | ||
201 | |||
202 | if (sectornum<dataarea) { | ||
203 | // A cluster number of a sector outside the data area was requested. | ||
204 | return CLUSTER_UNDEFINED; | ||
205 | } | ||
206 | |||
207 | __uint32 unoffsetsector=sectornum-dataarea; | ||
208 | __uint32 sectorspercluster= | ||
209 | Convert::getint32(sector_boot,FSINFO_BLOCKSIZE_IN_SECTORS) | ||
210 | * Convert::getint32(sector_boot,FSINFO_AUDIOBLOCKS_PER_CLUSTER); | ||
211 | __uint32 firstsectorofcluster=unoffsetsector-(unoffsetsector%sectorspercluster); | ||
212 | __uint32 cluster=firstsectorofcluster/sectorspercluster; | ||
213 | return cluster; | ||
214 | } | ||
215 | |||
216 | __uint32 hd24fs::getnextfreesector(__uint32 cluster) | ||
217 | { | ||
218 | if (cluster==CLUSTER_UNDEFINED) { | ||
219 | __uint32 result=getnextfreesectorword(); | ||
220 | #if (HD24FSDEBUG==1) | ||
221 | cout << result << endl; | ||
222 | #endif | ||
223 | return result; | ||
224 | } | ||
225 | if (isfreecluster(cluster+1,§ors_driveusage[0])) | ||
226 | { | ||
227 | return cluster2sector(cluster+1); | ||
228 | } | ||
229 | return getnextfreesectorword(); | ||
230 | } | ||
231 | |||
232 | __uint32 hd24fs::getnextfreesectorword() | ||
233 | { | ||
234 | __uint32 cluster=getnextfreeclusterword(); | ||
235 | if (cluster==CLUSTER_UNDEFINED) { | ||
236 | return 0; | ||
237 | } | ||
238 | return cluster2sector(cluster); | ||
239 | } | ||
240 | |||
241 | __uint32 hd24fs::getnextfreeclusterword() | ||
242 | { | ||
243 | getsectors_driveusage(); | ||
244 | __uint32 driveusagecount=driveusagesectorcount(); | ||
245 | __uint32 driveusagewords=driveusagecount*(512/4); | ||
246 | |||
247 | // For performance reasons, we start searching | ||
248 | // at last result+1 (this will typically result | ||
249 | // in an immediate hit). | ||
250 | // Wrap around to cluster 0 if nothing found. | ||
251 | |||
252 | #if (HD24FSDEBUG==1) | ||
253 | cout << " start search at " << nextfreeclusterword << endl; | ||
254 | #endif | ||
255 | __uint32 i=nextfreeclusterword; | ||
256 | __uint32 initsec=i; | ||
257 | |||
258 | bool foundfree=false; | ||
259 | while (i<driveusagewords) { | ||
260 | if (Convert::getint32(§ors_driveusage[0],i*4)==0) { | ||
261 | foundfree=true; | ||
262 | break; | ||
263 | } | ||
264 | i++; | ||
265 | } | ||
266 | if (!foundfree) { | ||
267 | if (initsec==0) { | ||
268 | // we didnt find anything although | ||
269 | // we started searching at cluster 0. | ||
270 | return CLUSTER_UNDEFINED; | ||
271 | } else { | ||
272 | // we didnt find anything but started | ||
273 | // searching at a cluster>0. Wrap around. | ||
274 | nextfreeclusterword=0; | ||
275 | return getnextfreeclusterword(); | ||
276 | } | ||
277 | } | ||
278 | // we found a (set of 32) free cluster(s). | ||
279 | nextfreeclusterword=i; | ||
280 | return (i*32); | ||
281 | } | ||
282 | |||
283 | unsigned long hd24fs::getlastsectornum() | ||
284 | { | ||
285 | #if (HD24FSDEBUG==1) | ||
286 | cout <<"hd24fs::getlastsectornum()" << endl; | ||
287 | #endif | ||
288 | // cache result. | ||
289 | if (gotlastsectornum==false) { | ||
290 | foundlastsectornum=getlastsectornum(devhd24); | ||
291 | gotlastsectornum=true; | ||
292 | } | ||
293 | return foundlastsectornum; | ||
294 | } | ||
295 | |||
296 | void hd24fs::setwavefixmode(int mode) | ||
297 | { | ||
298 | wavefixmode=mode; | ||
299 | } | ||
300 | |||
301 | void hd24fs::setmaintenancemode(int mode) | ||
302 | { | ||
303 | maintenancemode=mode; | ||
304 | } | ||
305 | |||
306 | int hd24fs::getmaintenancemode() | ||
307 | { | ||
308 | return maintenancemode; | ||
309 | } | ||
310 | |||
311 | string* hd24fs::getdevicename() { | ||
312 | |||
313 | return this->devicename; | ||
314 | } | ||
315 | |||
316 | void hd24fs::setdevicename(const char* orig,string* devname) | ||
317 | { | ||
318 | if (this->devicename!=NULL) { | ||
319 | delete this->devicename; | ||
320 | this->devicename=NULL; | ||
321 | } | ||
322 | this->devicename=new string(devname->c_str()); | ||
323 | } | ||
324 | |||
325 | unsigned long hd24fs::getlastsectornum(FSHANDLE handle) | ||
326 | { | ||
327 | #if (HD24FSDEBUG==1) | ||
328 | cout <<"hd24fs::getlastsectornum(FSHANDLE handle)" << endl; | ||
329 | #endif | ||
330 | #if defined(LINUX) || defined(DARWIN) | ||
331 | __uint64 curroff=lseek64(handle,0,SEEK_CUR); | ||
332 | __uint64 sectors=(lseek64(handle,0,SEEK_END)+1)>>9; | ||
333 | lseek64(handle,curroff,SEEK_SET); | ||
334 | return sectors-1; | ||
335 | #endif | ||
336 | /* unfortunately, apart from other functions being needed | ||
337 | * to read 64 bit files, the elegant solution above won't | ||
338 | * work on Windows, because it is not possible to | ||
339 | * request the file size of a device. | ||
340 | */ | ||
341 | |||
342 | #ifdef WINDOWS | ||
343 | unsigned char buffer[2048]; | ||
344 | LARGE_INTEGER lizero; | ||
345 | lizero.QuadPart=0; | ||
346 | LARGE_INTEGER saveoff; | ||
347 | LARGE_INTEGER filelen; | ||
348 | filelen.QuadPart=0; | ||
349 | SetFilePointerEx(handle,lizero,&saveoff,FILE_CURRENT); // save offset | ||
350 | /* If things would work properly, the following would | ||
351 | * not only work for regular files, but also for devices. | ||
352 | * Perhaps the next version of Windows has proper hardware | ||
353 | * abstraction and this will magically start working. | ||
354 | */ | ||
355 | if (0!=SetFilePointerEx(handle,lizero,&filelen,FILE_END)) { | ||
356 | SetFilePointerEx(handle,saveoff,NULL,FILE_BEGIN); // restore offset | ||
357 | return ((filelen.QuadPart)/512); | ||
358 | } | ||
359 | SetFilePointerEx(handle,saveoff,NULL,FILE_BEGIN); // restore offset | ||
360 | #if (HD24FSDEBUG==1) | ||
361 | cout << "fileptr method failed" << endl; | ||
362 | #endif | ||
363 | /* The proper way to do things has failed (probably because | ||
364 | * we are dealing with a device file instead of with a | ||
365 | * regular one. | ||
366 | */ | ||
367 | |||
368 | /* TODO: Before trying a raw sectornum scan, | ||
369 | we can still check if we're dealing with a valid | ||
370 | superblock, not using a headerfile and checking if | ||
371 | the last sector as indicated by the superblock points | ||
372 | to a copy of that superblock. This won't work on a raw | ||
373 | drive, of course, but will provide a reasonably safe | ||
374 | workaround for valid HD24 drives. */ | ||
375 | |||
376 | /* The workaround has also failed, so we need to perform | ||
377 | raw drive size detection. Windows does not have a reliable | ||
378 | way to get the real LBA sector count, so we need to perform | ||
379 | the following semi-smart trick (if you have a better idea that | ||
380 | works on all windows versions and all drive types, | ||
381 | I'd be thrilled to know!) | ||
382 | |||
383 | - First, iterate reading sector numbers until it fails. | ||
384 | To keep speed acceptable, multiply sector number by 2 | ||
385 | each time. | ||
386 | - After failed read, do a binary search between the | ||
387 | failed read sector number and the sector number of | ||
388 | the last successful read. | ||
389 | - As the drive MUST be aware of its own size, this will | ||
390 | give the real sector count of the drive. | ||
391 | */ | ||
392 | lizero.QuadPart=0; | ||
393 | saveoff.QuadPart=0; | ||
394 | |||
395 | LARGE_INTEGER maxbytes; | ||
396 | maxbytes.QuadPart=0; | ||
397 | SetFilePointerEx(handle,lizero,&saveoff,FILE_CURRENT); // save offset | ||
398 | |||
399 | long bytesread=1; | ||
400 | unsigned long trysector=1; | ||
401 | unsigned long oldtrysector=1; | ||
402 | int drivetoosmall=1; | ||
403 | bytesread=readsectors(handle,trysector,buffer,1); // raw/audio read (no fstfix needed) | ||
404 | unsigned long lastok=0; | ||
405 | unsigned long firstfail=0; | ||
406 | //int dummy; | ||
407 | /* This loop doubles the sector number. Actually stays at 2^n-1, | ||
408 | * this will likely perform better than 2^n because chances are | ||
409 | * greater that it stays below disk boundaries, preventing slow | ||
410 | * timeouts. | ||
411 | */ | ||
412 | while (bytesread>0) | ||
413 | { | ||
414 | #if (HD24FSDEBUG==1) | ||
415 | cout << "trysector=" << trysector << endl; | ||
416 | #endif | ||
417 | // cin >> dummy; | ||
418 | drivetoosmall=0; | ||
419 | oldtrysector=trysector; | ||
420 | trysector=trysector*2+1; // count will be 1,3,7,15,31,... =(2^n)-1 | ||
421 | if (oldtrysector==trysector) | ||
422 | { | ||
423 | // x*2+1 yields x - this means all | ||
424 | // bits are turned on and we overflow. | ||
425 | // So we're at 4 tera limit. | ||
426 | // 4 terabyte and still nothing found? hmmmm | ||
427 | SetFilePointerEx(handle,saveoff,NULL,FILE_BEGIN); | ||
428 | return 0; | ||
429 | } | ||
430 | bytesread=0; | ||
431 | bytesread=readsectors(handle,trysector,buffer,1); // raw/audio read (no fstfix needed) | ||
432 | #if (HD24FSDEBUG==1) | ||
433 | cout << " bytesread=" <<bytesread << endl; | ||
434 | #endif | ||
435 | if (bytesread>0) { | ||
436 | lastok=trysector; | ||
437 | } else { | ||
438 | firstfail=trysector; | ||
439 | } | ||
440 | } | ||
441 | /* We have the sector number of the last successful read and | ||
442 | * of the failed read. Time to do a binary search. */ | ||
443 | unsigned long lowerbound=lastok; | ||
444 | #if (HD24FSDEBUG==1) | ||
445 | cout << "lastok=" << lastok << endl; | ||
446 | cout << "firstfaiL=" << firstfail << endl; | ||
447 | |||
448 | #endif | ||
449 | if (lastok==0) | ||
450 | { | ||
451 | if (firstfail==0) | ||
452 | { | ||
453 | return 0; | ||
454 | } | ||
455 | } | ||
456 | unsigned long upperbound=lastok*2; | ||
457 | unsigned long midpos=0; | ||
458 | while (lowerbound<=upperbound) | ||
459 | { | ||
460 | //midpos=lowerbound+floor((upperbound-lowerbound)/2); | ||
461 | midpos=lowerbound+(__uint32)floor((upperbound-lowerbound)/8); | ||
462 | // prefer asymmetrical search due to time out when | ||
463 | // searching past upperbound | ||
464 | // cout << "try=" << midpos << endl; | ||
465 | bytesread=readsectors(handle,midpos,buffer,1); // raw/audio read (no fstfix needed) | ||
466 | if (bytesread>0) { | ||
467 | lowerbound=midpos+1; | ||
468 | } else { | ||
469 | // could not read midpos, | ||
470 | // so upperbound is before that. | ||
471 | upperbound=midpos-1; | ||
472 | } | ||
473 | } | ||
474 | if (midpos==lowerbound) | ||
475 | { | ||
476 | midpos--; | ||
477 | } | ||
478 | /* midpos is now last sector number. counting starts at sector 0 | ||
479 | * so total number of sectors is one more. */ | ||
480 | midpos++; | ||
481 | SetFilePointerEx(handle,saveoff,&saveoff,FILE_BEGIN); //restore | ||
482 | |||
483 | __uint64 sectors=midpos; | ||
484 | // cout << "found " <<sectors << "sectors " <<endl; | ||
485 | return sectors; | ||
486 | #endif | ||
487 | } | ||
488 | |||
489 | /* The hd24raw class provides sector level access to hd24 disks | ||
490 | * which is functionality that is shielded off in hd24fs. | ||
491 | */ | ||
492 | |||
493 | __uint32 hd24raw::songsondisk() | ||
494 | { | ||
495 | return fsys->songsondisk(); | ||
496 | } | ||
497 | |||
498 | __uint32 hd24raw::getlastsectornum() | ||
499 | { | ||
500 | return fsys->getlastsectornum(); | ||
501 | } | ||
502 | |||
503 | __uint32 hd24raw::getprojectsectornum(__uint32 x) | ||
504 | { | ||
505 | return fsys->getprojectsectornum(x); | ||
506 | } | ||
507 | |||
508 | __uint32 hd24raw::quickformat(char* message) | ||
509 | { | ||
510 | return fsys->quickformat(message); | ||
511 | } | ||
512 | |||
513 | unsigned long hd24raw::getnextfreesector(__uint32 cluster) | ||
514 | { | ||
515 | return fsys->getnextfreesector(cluster); | ||
516 | } | ||
517 | |||
518 | hd24raw::hd24raw(hd24fs* p_fsys) | ||
519 | { | ||
520 | fsys=p_fsys; | ||
521 | } | ||
522 | |||
523 | long hd24raw::readsectors(unsigned long secnum, unsigned char* buffer,int sectors) | ||
524 | { | ||
525 | return fsys->readsectors(fsys->devhd24, secnum, buffer,sectors); | ||
526 | } | ||
527 | |||
528 | long hd24raw::writesectors(unsigned long secnum, unsigned char* buffer,int sectors) | ||
529 | { | ||
530 | return fsys->writesectors(fsys->devhd24, secnum, buffer,sectors); | ||
531 | }; | ||
532 | |||
533 | bool hd24fs::isinvalidhandle(FSHANDLE handle) | ||
534 | { | ||
535 | #ifdef WINDOWS | ||
536 | if (handle==FSHANDLE_INVALID) { | ||
537 | return true; | ||
538 | } | ||
539 | #endif | ||
540 | #if defined(LINUX) || defined(DARWIN) | ||
541 | if (handle==0) { | ||
542 | return true; | ||
543 | } | ||
544 | if (handle==FSHANDLE_INVALID) { | ||
545 | return true; | ||
546 | } | ||
547 | #endif | ||
548 | return false; | ||
549 | } | ||
550 | |||
551 | bool hd24fs::isexistingdevice(string* devname) | ||
552 | { | ||
553 | #if defined(LINUX) || defined(DARWIN) | ||
554 | #if (HD24FSDEBUG==1) | ||
555 | cout << "try open device " << devname->c_str() << endl; | ||
556 | #endif | ||
557 | FSHANDLE handle=open64(devname->c_str(),MODE_RDONLY); //read binary | ||
558 | #endif | ||
559 | #ifdef WINDOWS | ||
560 | FSHANDLE handle=CreateFile(devname->c_str(),MODE_RDONLY, | ||
561 | FILE_SHARE_READ|FILE_SHARE_WRITE, | ||
562 | NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL); | ||
563 | #endif | ||
564 | if (!isinvalidhandle(handle)) return true; | ||
565 | return false; | ||
566 | } | ||
567 | |||
568 | FSHANDLE hd24fs::findhd24device(int mode,string* devname,bool force,bool tryharder) | ||
569 | { | ||
570 | #if (HD24FSDEBUG_DEVSCAN==1) | ||
571 | cout << "FSHANDLE hd24fs::findhd24device(" << mode << ", " << *devname << ", force=" << force << ",tryharder=" << tryharder <<")" << endl; | ||
572 | #endif | ||
573 | unsigned char findhdbuf[1024]; | ||
574 | unsigned char compare1buf[1024]; | ||
575 | unsigned char compare2buf[1024]; | ||
576 | #if defined(LINUX) | ||
577 | FSHANDLE handle=open64(devname->c_str(),mode,0); //read binary | ||
578 | #endif | ||
579 | #if defined(DARWIN) | ||
580 | FSHANDLE handle=open64(devname->c_str(),mode); //read binary | ||
581 | #endif | ||
582 | #ifdef WINDOWS | ||
583 | #if (HD24FSDEBUG_DEVSCAN==1) | ||
584 | cout << "Mode=" << mode << endl; | ||
585 | #endif | ||
586 | FSHANDLE handle=CreateFile(devname->c_str(),mode, | ||
587 | FILE_SHARE_READ|FILE_SHARE_WRITE, | ||
588 | NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL); | ||
589 | #endif | ||
590 | |||
591 | if (isinvalidhandle(handle)) { | ||
592 | if (mode==MODE_RDWR) | ||
593 | { | ||
594 | // attempt fallback to read-only mode | ||
595 | // (for CDROM/DVD devices etc) | ||
596 | mode=MODE_RDONLY; | ||
597 | #if defined(LINUX) || defined(DARWIN) | ||
598 | handle=open64(devname->c_str(),mode); //read binary | ||
599 | #endif | ||
600 | #ifdef WINDOWS | ||
601 | #if (HD24FSDEBUG==1) | ||
602 | // cout << "Mode=" << mode << endl; | ||
603 | #endif | ||
604 | handle=CreateFile(devname->c_str(),mode, | ||
605 | FILE_SHARE_READ|FILE_SHARE_WRITE, | ||
606 | NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL); | ||
607 | #endif | ||
608 | |||
609 | } | ||
610 | |||
611 | |||
612 | } | ||
613 | |||
614 | if (isinvalidhandle(handle)) { | ||
615 | return handle; | ||
616 | } | ||
617 | |||
618 | // can open device. | ||
619 | __uint32 sectornum=0; | ||
620 | if (tryharder) { | ||
621 | sectornum=getlastsectornum(handle); | ||
622 | } | ||
623 | |||
624 | readsector_noheader(handle,sectornum,findhdbuf); // fstfix follows | ||
625 | fstfix(findhdbuf,512); | ||
626 | string* fstype=Convert::readstring(findhdbuf,0,8); | ||
627 | bool isadat=false; | ||
628 | |||
629 | if (*fstype=="ADAT FST") { | ||
630 | /* Okay, but if we are 'trying harder' we can run into | ||
631 | a false positive for old HD24 drives that are now in | ||
632 | use as OS drive. So we'll demand that the second and | ||
633 | secondlast sector are equal. | ||
634 | */ | ||
635 | if (tryharder) | ||
636 | { | ||
637 | readsector_noheader(handle,sectornum-1,compare1buf); | ||
638 | readsector_noheader(handle,1,compare2buf); | ||
639 | if (memcmp(compare1buf,compare2buf,512)==0) | ||
640 | { | ||
641 | isadat=true; | ||
642 | } | ||
643 | else | ||
644 | { | ||
645 | /* Drive may have been an ADAT drive, | ||
646 | but no longer is. If it is in fact an | ||
647 | ADAT drive but corrupted, it is still | ||
648 | possible to force detection using force | ||
649 | mode. Give it another chance; do not | ||
650 | enable write prevention for now. | ||
651 | */ | ||
652 | isadat=false; | ||
653 | } | ||
654 | } | ||
655 | else | ||
656 | { | ||
657 | isadat=true; | ||
658 | } | ||
659 | } | ||
660 | delete fstype; | ||
661 | |||
662 | if (isadat) return handle; | ||
663 | |||
664 | if (force) | ||
665 | { | ||
666 | forcemode=true; | ||
667 | m_isOpen=true; | ||
668 | this->writeprotected=true; // TODO: unless expert mode is enabled too. May also be overridden to allow formatting. | ||
669 | return handle; | ||
670 | } | ||
671 | hd24closedevice(handle); | ||
672 | return FSHANDLE_INVALID; | ||
673 | } | ||
674 | |||
675 | unsigned long hd24fs::hd24devicecount() | ||
676 | { | ||
677 | /* Attempt to auto-detect a hd24 disk on all IDE and SCSI devices. | ||
678 | (this should include USB and firewire) */ | ||
679 | FSHANDLE handle; | ||
680 | int devcount=0; | ||
681 | #if (HD24FSDEBUG==1) | ||
682 | cout << "====PERFORMING DEVICE COUNT====" << endl; | ||
683 | #endif | ||
684 | hd24devicenamegenerator* dng=new hd24devicenamegenerator(); | ||
685 | dng->imagedir(this->imagedir); | ||
686 | |||
687 | __uint32 totnames=dng->getnumberofnames(); | ||
688 | // cout << totnames << " devices" << endl; | ||
689 | for (__uint32 j=0;j<2;j++) | ||
690 | { | ||
691 | // 2 loops: one to try, one to try harder | ||
692 | // first loop searches strictly valid devices | ||
693 | // second loop searches for possibly corrupted devices | ||
694 | bool tryharder=false; | ||
695 | if (j==1) { | ||
696 | tryharder=true; | ||
697 | } | ||
698 | for (__uint32 i=0;i<totnames;i++) | ||
699 | { | ||
700 | string* devname=dng->getdevicename(i); | ||
701 | handle=findhd24device(MODE_RDONLY,devname,false,tryharder); | ||
702 | #if (HD24FSDEBUG_DEVSCAN==1) | ||
703 | cout << "try device no " <<i << "with name" << *devname << "..."; | ||
704 | #endif | ||
705 | delete (devname); | ||
706 | if (!(isinvalidhandle(handle))) | ||
707 | { | ||
708 | devcount++; | ||
709 | // cout << "found" << endl; | ||
710 | hd24closedevice(handle); | ||
711 | } else { | ||
712 | // cout << "nope." << endl; | ||
713 | } | ||
714 | } | ||
715 | |||
716 | if (devcount>0) { | ||
717 | break; | ||
718 | } | ||
719 | } | ||
720 | #if (HD24FSDEBUG==1) | ||
721 | cout << "====END OF DEVICE COUNT, " << devcount << " DEVICES FOUND ====" << endl; | ||
722 | #endif | ||
723 | delete (dng); | ||
724 | return devcount; | ||
725 | } | ||
726 | |||
727 | void hd24fs::setimagedir(const char* newdir) | ||
728 | { | ||
729 | #if (HD24FSDEBUG==1) | ||
730 | if (newdir==NULL) | ||
731 | { | ||
732 | cout << "hd24fs::setimagedir(NULL)"<< endl; | ||
733 | } | ||
734 | else | ||
735 | { | ||
736 | cout << "hd24fs::setimagedir("<<newdir<<")"<< endl; | ||
737 | } | ||
738 | #endif | ||
739 | |||
740 | if (this->imagedir!=NULL) | ||
741 | { | ||
742 | free ((void*)imagedir); | ||
743 | this->imagedir=NULL; | ||
744 | } | ||
745 | |||
746 | if (newdir!=NULL) | ||
747 | { | ||
748 | this->imagedir=(char*)malloc(strlen(newdir)+1); | ||
749 | if (this->imagedir!=NULL) | ||
750 | { | ||
751 | strncpy((char*)imagedir,newdir,strlen(newdir)+1); | ||
752 | } | ||
753 | } | ||
754 | |||
755 | return; //return (const char*)imagedir; | ||
756 | } | ||
757 | |||
758 | FSHANDLE hd24fs::findhd24device(int mode,int base0devnum) | ||
759 | { | ||
760 | #if (HD24FSDEBUG_DEVSCAN==1) | ||
761 | cout << "hd24fs::findhd24device(" << mode << "," << base0devnum << ")" << endl; | ||
762 | #endif | ||
763 | // TODO: Reduce code duplication in this subroutine | ||
764 | // and hd24devicecount | ||
765 | /* Attempt to auto-detect a hd24 disk on all known | ||
766 | IDE and SCSI devices. (this should include USB | ||
767 | and firewire) */ | ||
768 | int currdev=0; | ||
769 | FSHANDLE handle; | ||
770 | hd24devicenamegenerator* dng=new hd24devicenamegenerator(); | ||
771 | dng->imagedir(this->imagedir); | ||
772 | |||
773 | __uint32 totnames=dng->getnumberofnames(); | ||
774 | #if (HD24FSDEBUG==1) | ||
775 | cout << totnames << " devices" << endl; | ||
776 | #endif | ||
777 | for (__uint32 j=0;j<2;j++) | ||
778 | { | ||
779 | // 2 loops: one to try, one to try harder | ||
780 | // first loop searches strictly valid devices | ||
781 | // second loop searches for possibly corrupted devices | ||
782 | |||
783 | bool tryharder=false; | ||
784 | if (j==1) { | ||
785 | tryharder=true; | ||
786 | } | ||
787 | |||
788 | for (__uint32 i=0;i<totnames;i++) | ||
789 | { | ||
790 | string* devname=dng->getdevicename(i); | ||
791 | handle=findhd24device(mode,devname,false,tryharder); | ||
792 | |||
793 | if (!(isinvalidhandle(handle))) { | ||
794 | if (currdev==base0devnum) { | ||
795 | // String "3" indicates origin, i.e. | ||
796 | // who is setting the device name. | ||
797 | // Useful for debugging purposes. | ||
798 | setdevicename("3",devname); | ||
799 | deviceid=i; | ||
800 | p_mode=mode; | ||
801 | delete (devname); | ||
802 | delete (dng); | ||
803 | return handle; | ||
804 | } | ||
805 | hd24closedevice(handle); | ||
806 | currdev++; | ||
807 | } | ||
808 | delete (devname); | ||
809 | } | ||
810 | } | ||
811 | delete (dng); | ||
812 | return FSHANDLE_INVALID; | ||
813 | } | ||
814 | |||
815 | void hd24fs::hd24closedevice(FSHANDLE handle) { | ||
816 | #if defined(LINUX) || defined(DARWIN) | ||
817 | close(handle); | ||
818 | #endif | ||
819 | #ifdef WINDOWS | ||
820 | CloseHandle(handle); | ||
821 | #endif | ||
822 | } | ||
823 | |||
824 | FSHANDLE hd24fs::findhd24device(int mode) | ||
825 | { | ||
826 | /* Attempt to auto-detect a hd24 disk on all IDE and SCSI devices. | ||
827 | (this should include USB and firewire) */ | ||
828 | return findhd24device(mode,0); | ||
829 | } | ||
830 | |||
831 | FSHANDLE hd24fs::findhd24device() | ||
832 | { | ||
833 | return findhd24device(MODE_RDONLY); | ||
834 | } | ||
835 | |||
836 | int hd24fs::gettransportstatus() | ||
837 | { | ||
838 | return this->transportstatus; | ||
839 | } | ||
840 | |||
841 | void hd24fs::settransportstatus(int newstatus) | ||
842 | { | ||
843 | this->transportstatus=newstatus; | ||
844 | } | ||
845 | |||
846 | int hd24fs::getdeviceid() | ||
847 | { | ||
848 | return deviceid; | ||
849 | } | ||
850 | |||
851 | void hd24fs::initvars() | ||
852 | { | ||
853 | this->deviceid=-1; | ||
854 | this->writeprotected=false; // by default allow writes. | ||
855 | // can be disabled if corrupt | ||
856 | // state is detected. | ||
857 | this->transportstatus=TRANSPORTSTATUS_STOP; | ||
858 | this->imagedir=NULL; | ||
859 | this->nextfreeclusterword=0; | ||
860 | this->gotlastsectornum=false; | ||
861 | this->foundlastsectornum=0; | ||
862 | this->forcemode=false; | ||
863 | this->headersectors=0; | ||
864 | sector_boot=NULL; | ||
865 | sector_diskinfo=NULL; | ||
866 | sectors_driveusage=NULL; | ||
867 | sectors_orphan=NULL; | ||
868 | sectors_songusage=NULL; | ||
869 | projlist=NULL; | ||
870 | this->m_isOpen=false; | ||
871 | this->allinput=false; | ||
872 | this->autoinput=false; | ||
873 | this->wavefixmode=false; | ||
874 | this->formatting=false; | ||
875 | this->maintenancemode=false; | ||
876 | this->headermode=false; | ||
877 | this->devicename=NULL; | ||
878 | this->highestFSsectorwritten=0; | ||
879 | // 0x10c76 is last sector of song/project area (without undo buffer) | ||
880 | return; | ||
881 | } | ||
882 | |||
883 | hd24fs::hd24fs(const char* imagedir,int mode) | ||
884 | { | ||
885 | initvars(); | ||
886 | setimagedir(imagedir); | ||
887 | devicename=new string(""); | ||
888 | devhd24=findhd24device(mode); | ||
889 | if (!(isinvalidhandle(devhd24))) { | ||
890 | m_isOpen=true; | ||
891 | p_mode=mode; | ||
892 | } | ||
893 | return; | ||
894 | } | ||
895 | |||
896 | hd24fs::hd24fs(const char* imagedir,int mode,int base0devnum) | ||
897 | { | ||
898 | #if (HD24FSDEBUG==1) | ||
899 | cout << "hd24fs::hd24fs(" << mode << "," << base0devnum << ")" << endl; | ||
900 | #endif | ||
901 | initvars(); | ||
902 | setimagedir(imagedir); | ||
903 | devicename=new string(""); | ||
904 | devhd24=findhd24device(mode,base0devnum); | ||
905 | if (!(isinvalidhandle(devhd24))) { | ||
906 | m_isOpen=true; | ||
907 | p_mode=mode; | ||
908 | } | ||
909 | return; | ||
910 | } | ||
911 | |||
912 | hd24fs::hd24fs(const char* imagedir,int mode,string* devname,bool force) | ||
913 | { | ||
914 | initvars(); | ||
915 | setimagedir(imagedir); | ||
916 | devicename=new string(devname->c_str()); | ||
917 | bool tryharder=false; | ||
918 | devhd24=findhd24device(mode,devname,force,tryharder); | ||
919 | if (!(isinvalidhandle(devhd24))) { | ||
920 | m_isOpen=true; | ||
921 | p_mode=mode; | ||
922 | } | ||
923 | return; | ||
924 | } | ||
925 | |||
926 | hd24fs::hd24fs(const char* imagedir) | ||
927 | { | ||
928 | initvars(); | ||
929 | setimagedir(imagedir); | ||
930 | devicename=new string(""); | ||
931 | devhd24=findhd24device(MODE_RDONLY); | ||
932 | if (!(isinvalidhandle(devhd24))) { | ||
933 | m_isOpen=true; | ||
934 | p_mode=MODE_RDONLY; | ||
935 | } | ||
936 | return; | ||
937 | } | ||
938 | |||
939 | hd24fs::~hd24fs() | ||
940 | { | ||
941 | #if (HD24FSDEBUG==1) | ||
942 | cout << "Deleting devicename" << endl; | ||
943 | #endif | ||
944 | if (devicename!=NULL) { | ||
945 | delete devicename; | ||
946 | devicename=NULL; | ||
947 | } | ||
948 | #if (HD24FSDEBUG==1) | ||
949 | cout << "Close FS handle" << endl; | ||
950 | #endif | ||
951 | if (isOpen()) | ||
952 | { | ||
953 | hd24close(); | ||
954 | } | ||
955 | #if (HD24FSDEBUG==1) | ||
956 | cout << "Free superblock mem" << endl; | ||
957 | #endif | ||
958 | if (sector_boot!=NULL) | ||
959 | { | ||
960 | memutils::myfree("sectors_boot",sector_boot); | ||
961 | sector_boot=NULL; | ||
962 | } | ||
963 | #if (HD24FSDEBUG==1) | ||
964 | cout << "Free diskinfo mem" << endl; | ||
965 | #endif | ||
966 | if (sector_diskinfo!=NULL) | ||
967 | { | ||
968 | memutils::myfree("sectors_diskinfo",sector_diskinfo); | ||
969 | sector_diskinfo=NULL; | ||
970 | } | ||
971 | #if (HD24FSDEBUG==1) | ||
972 | cout << "Free drive usage mem" << endl; | ||
973 | #endif | ||
974 | if (sectors_driveusage!=NULL) | ||
975 | { | ||
976 | memutils::myfree("sectors_driveusage",sectors_driveusage); | ||
977 | sectors_driveusage=NULL; | ||
978 | } | ||
979 | #if (HD24FSDEBUG==1) | ||
980 | cout << "Free orphan sectors mem" << endl; | ||
981 | #endif | ||
982 | if (sectors_orphan!=NULL) | ||
983 | { | ||
984 | memutils::myfree("sectors_orphan",sectors_orphan); | ||
985 | sectors_orphan=NULL; | ||
986 | } | ||
987 | #if (HD24FSDEBUG==1) | ||
988 | cout << "Free song usage sectors mem" << endl; | ||
989 | #endif | ||
990 | if (sectors_songusage!=NULL) | ||
991 | { | ||
992 | memutils::myfree("sectors_songusage",sectors_songusage); | ||
993 | sectors_songusage=NULL; | ||
994 | }; | ||
995 | // commit? | ||
996 | } | ||
997 | |||
998 | bool hd24fs::isOpen() | ||
999 | { | ||
1000 | if (this->m_isOpen) | ||
1001 | { | ||
1002 | return true; | ||
1003 | } | ||
1004 | return false; | ||
1005 | } | ||
1006 | |||
1007 | void hd24fs::hd24close() | ||
1008 | { | ||
1009 | // TODO: At the point that we start supporting | ||
1010 | // write access, we will need to flush and close | ||
1011 | // the device here. | ||
1012 | |||
1013 | hd24closedevice(this->devhd24); | ||
1014 | } | ||
1015 | |||
1016 | void hd24fs::fstfix(unsigned char * bootblock,int fixsize) | ||
1017 | { | ||
1018 | if (bootblock==NULL) return; | ||
1019 | if (fixsize<=0) return; | ||
1020 | #if (HD24FSDEBUG==1) | ||
1021 | cout << "fstfix("<<bootblock<<","<<fixsize/512 <<"*512)"<< endl; | ||
1022 | #endif | ||
1023 | for (int i=0;i<fixsize;i+=4) | ||
1024 | { | ||
1025 | unsigned char a=bootblock[i]; | ||
1026 | unsigned char b=bootblock[i+1]; | ||
1027 | unsigned char c=bootblock[i+2]; | ||
1028 | unsigned char d=bootblock[i+3]; | ||
1029 | bootblock[i]=d; | ||
1030 | bootblock[i+1]=c; | ||
1031 | bootblock[i+2]=b; | ||
1032 | bootblock[i+3]=a; | ||
1033 | } | ||
1034 | } | ||
1035 | |||
1036 | void hd24fs::hd24seek(FSHANDLE devhd24,__uint64 seekpos) { | ||
1037 | #if defined(LINUX) || defined(DARWIN) | ||
1038 | lseek64(devhd24,seekpos,SEEK_SET); | ||
1039 | #endif | ||
1040 | #ifdef WINDOWS | ||
1041 | // cout << "setfp to " <<seekpos << endl; | ||
1042 | LARGE_INTEGER li; | ||
1043 | li.HighPart=seekpos>>32; | ||
1044 | li.LowPart=seekpos%((__uint64)1<<32); | ||
1045 | //LowPart=seekpos% | ||
1046 | // SetFilePointer(devhd24,seekpos,NULL,FILE_BEGIN); | ||
1047 | SetFilePointerEx(devhd24,li,NULL,FILE_BEGIN); | ||
1048 | // TODO: SetFilePointer vs SetFilePointerEx | ||
1049 | // DWORD SetFilePointer( | ||
1050 | // HANDLE hFile, | ||
1051 | // LONG lDistanceToMove, | ||
1052 | // PLONG lpDistanceToMoveHigh, | ||
1053 | // DWORD dwMoveMethod | ||
1054 | // ); | ||
1055 | // | ||
1056 | // vs. | ||
1057 | // BOOL SetFilePointerEx( | ||
1058 | // HANDLE hFile, | ||
1059 | // LARGE_INTEGER liDistanceToMove, | ||
1060 | // PLARGE_INTEGER lpNewFilePointer, | ||
1061 | // DWORD dwMoveMethod | ||
1062 | // ); | ||
1063 | // | ||
1064 | #endif | ||
1065 | return; | ||
1066 | } | ||
1067 | |||
1068 | long hd24fs::writesectors(FSHANDLE devhd24,unsigned long sectornum,unsigned char * buffer,int sectors) | ||
1069 | { | ||
1070 | ////// | ||
1071 | // this bit keeps track of the highest FS sector written | ||
1072 | // to keep commit times acceptable: commit function will then | ||
1073 | // only backup up to the highest sector used. | ||
1074 | // (this is still suboptimal performance-wise but requires | ||
1075 | // a minimum of memory and administration during writes). | ||
1076 | __uint32 lastsec=sectornum+(sectors-1); | ||
1077 | if (lastsec<=0x10c76) | ||
1078 | { | ||
1079 | // 0x10c76 is last sector of song/project area (without | ||
1080 | // undo buffer). TODO: calculate based on superblock. info. | ||
1081 | if (lastsec>highestFSsectorwritten) | ||
1082 | { | ||
1083 | highestFSsectorwritten=lastsec; | ||
1084 | } | ||
1085 | } | ||
1086 | ////// | ||
1087 | |||
1088 | #if (HD24FSDEBUG_WRITE==1) | ||
1089 | cout << " writesectors sectornum " << sectornum << ", sectorcount=" << sectors << endl; | ||
1090 | #endif | ||
1091 | if (this!=NULL) | ||
1092 | { | ||
1093 | if (this->writeprotected) | ||
1094 | { | ||
1095 | #if (HD24FSDEBUG_WRITE==1) | ||
1096 | cout << "Write protected- not writing. " << endl; | ||
1097 | #endif | ||
1098 | return 0; | ||
1099 | } | ||
1100 | } | ||
1101 | FSHANDLE currdevice=devhd24; | ||
1102 | |||
1103 | #if (HD24FSDEBUG_WRITE==1) | ||
1104 | cout << "WRITESECTORS sec=" << sectornum << " buf=" << buffer << "#=" << sectors << endl; | ||
1105 | #endif | ||
1106 | int WRITESIZE=SECTORSIZE*sectors; // allows searching across sector boundaries | ||
1107 | |||
1108 | // cout << "headersectors=" << this->headersectors << "this=" <<this << endl; | ||
1109 | if (this!=NULL) | ||
1110 | { | ||
1111 | if ((this->headersectors)!=0) | ||
1112 | { | ||
1113 | // cout << "headermode enabled." << endl; | ||
1114 | // Header mode is active. Only allow writing over header area. | ||
1115 | if (sectornum<this->headersectors) | ||
1116 | { | ||
1117 | // cout << "Headermode enabled for sector " << sectornum << endl; | ||
1118 | currdevice=hd24header; | ||
1119 | |||
1120 | } else { | ||
1121 | // headermode is active yet caller is trying to write over drive | ||
1122 | // data area. We cannot allow this (for safety reasons). | ||
1123 | return 0; | ||
1124 | |||
1125 | // cout << "Headermode disabled for sector " << sectornum << endl; | ||
1126 | } | ||
1127 | } else { | ||
1128 | // cout << "Headermode disabled. " << sectornum << endl; | ||
1129 | } | ||
1130 | } | ||
1131 | |||
1132 | hd24seek(currdevice,(__uint64)sectornum*512); | ||
1133 | |||
1134 | #if defined(LINUX) || defined(DARWIN) || defined(__APPLE__) | ||
1135 | long bytes=pwrite64(currdevice,buffer,WRITESIZE,(__uint64)sectornum*512); //1,devhd24); | ||
1136 | // cout << "BYTES=" << bytes << endl; | ||
1137 | #endif | ||
1138 | #ifdef WINDOWS | ||
1139 | DWORD dummy; | ||
1140 | long bytes=0; | ||
1141 | if (WriteFile(currdevice,buffer,WRITESIZE,&dummy,NULL)) { | ||
1142 | bytes=WRITESIZE; | ||
1143 | }; | ||
1144 | #endif | ||
1145 | return bytes; | ||
1146 | } | ||
1147 | |||
1148 | long hd24fs::readsectors(FSHANDLE devhd24,unsigned long sectornum,unsigned char * buffer,int sectors) | ||
1149 | { | ||
1150 | FSHANDLE currdevice=devhd24; | ||
1151 | // The following prints the sector num in hex: | ||
1152 | #if (HD24FSDEBUG==1) | ||
1153 | /* string* x=this->p_convert->int32tohex(sectornum); | ||
1154 | cout << *x << endl; | ||
1155 | delete x; | ||
1156 | */ | ||
1157 | #endif | ||
1158 | |||
1159 | // cout << "headersectors=" << this->headersectors << "this=" <<this << endl; | ||
1160 | if ((this->headersectors)!=0) | ||
1161 | { | ||
1162 | // cout << "headermode enabled." << endl; | ||
1163 | if (sectornum<this->headersectors) | ||
1164 | { | ||
1165 | // cout << "Headermode enabled for sector " << sectornum << endl; | ||
1166 | currdevice=hd24header; | ||
1167 | } else { | ||
1168 | // cout << "Headermode disabled for sector " << sectornum << endl; | ||
1169 | } | ||
1170 | } else { | ||
1171 | // cout << "Headermode disabled. " << sectornum << endl; | ||
1172 | } | ||
1173 | hd24seek(currdevice,(__uint64)sectornum*SECTORSIZE); | ||
1174 | int READSIZE=SECTORSIZE*(sectors); | ||
1175 | #if defined(LINUX) || defined(DARWIN) | ||
1176 | long bytes_read=pread64(currdevice,buffer,READSIZE,(__uint64)sectornum*512); //1,currdevice); | ||
1177 | #endif | ||
1178 | #ifdef WINDOWS | ||
1179 | // cout << "Readsectors: num="<<sectornum<<"buffer available, numsecs=" <<sectors << endl; | ||
1180 | DWORD bytes_read; | ||
1181 | //long bytes=0; | ||
1182 | if( ReadFile(currdevice,buffer,READSIZE,&bytes_read,NULL)) { | ||
1183 | // cout << "read succes"<< bytes_read << "bytes" << endl; | ||
1184 | } else { | ||
1185 | // cout << "read fail" << endl; | ||
1186 | bytes_read = 0; | ||
1187 | } | ||
1188 | #endif | ||
1189 | return bytes_read; | ||
1190 | } | ||
1191 | |||
1192 | long hd24fs::readsector(FSHANDLE devhd24,unsigned long sectornum,unsigned char * bootblock) | ||
1193 | { | ||
1194 | return readsectors(devhd24,sectornum,bootblock,1); | ||
1195 | } | ||
1196 | |||
1197 | long hd24fs::readsector_noheader(hd24fs* currhd24,unsigned long sectornum,unsigned char * bootblock) | ||
1198 | { | ||
1199 | return readsector_noheader(currhd24->devhd24,sectornum,bootblock); | ||
1200 | } | ||
1201 | |||
1202 | long hd24fs::readsector_noheader(FSHANDLE devhd24,unsigned long sectornum,unsigned char * bootblock) | ||
1203 | { | ||
1204 | unsigned long headersecs=this->headersectors; | ||
1205 | this->headersectors=0; // disable header processing, if applies | ||
1206 | long number_read=readsectors(devhd24,sectornum,bootblock,1); | ||
1207 | this->headersectors=headersecs; // re-enable header processing | ||
1208 | return number_read; | ||
1209 | } | ||
1210 | |||
1211 | long hd24fs::writesector(FSHANDLE devhd24,unsigned long sectornum,unsigned char * bootblock) | ||
1212 | { | ||
1213 | return writesectors(devhd24,sectornum,bootblock,1); | ||
1214 | } | ||
1215 | |||
1216 | string* hd24fs::gethd24currentdir(int argc,char* argv[]) | ||
1217 | { | ||
1218 | /* For future use. We may save a file in the | ||
1219 | homedir of the user containing info about which | ||
1220 | "path" (project/songname/file format) was last | ||
1221 | selected by the user. | ||
1222 | */ | ||
1223 | |||
1224 | return new string("/"); | ||
1225 | } | ||
1226 | |||
1227 | string* hd24fs::gethd24currentdir() | ||
1228 | { | ||
1229 | return new string("/"); | ||
1230 | } | ||
1231 | |||
1232 | unsigned char* hd24fs::readdiskinfo() | ||
1233 | { | ||
1234 | #if (HD24FSDEBUG==1) | ||
1235 | cout << "Driveusage before readdiskinfo=" << (int)(this->sectors_driveusage) << endl; | ||
1236 | #endif | ||
1237 | // read disk info | ||
1238 | if (/*formatting||*/(sector_boot==NULL)) | ||
1239 | { | ||
1240 | this->readbootinfo(); | ||
1241 | } | ||
1242 | if (sector_diskinfo!=NULL) | ||
1243 | { | ||
1244 | memutils::myfree("readdiskinfo",sector_diskinfo); | ||
1245 | sector_diskinfo=NULL; | ||
1246 | } | ||
1247 | sector_diskinfo=(unsigned char *)memutils::mymalloc("readdiskinfo",1024,1); | ||
1248 | if (sector_diskinfo!=NULL) | ||
1249 | { | ||
1250 | readsector(devhd24,1,sector_diskinfo); // fstfix follows | ||
1251 | fstfix (sector_diskinfo,512); | ||
1252 | } | ||
1253 | #if (HD24FSDEBUG==1) | ||
1254 | cout << "Driveusage after readdiskinfo=" << (int)(this->sectors_driveusage) << endl; | ||
1255 | #endif | ||
1256 | return sector_diskinfo; | ||
1257 | } | ||
1258 | |||
1259 | bool hd24fs::useheaderfile(string headerfilename) | ||
1260 | { | ||
1261 | getsector_bootinfo(); | ||
1262 | if (sector_boot==NULL) | ||
1263 | { | ||
1264 | /* we haven't got a main device yet | ||
1265 | so we cannot apply a header to it */ | ||
1266 | return false; | ||
1267 | } | ||
1268 | // allow writing to header. | ||
1269 | #if defined(LINUX) || defined(DARWIN) | ||
1270 | FSHANDLE handle=open64(headerfilename.c_str(),MODE_RDWR); //read binary | ||
1271 | #endif | ||
1272 | #ifdef WINDOWS | ||
1273 | // cout << "Mode=" << mode << endl; | ||
1274 | FSHANDLE handle=CreateFile(headerfilename.c_str(),MODE_RDWR, | ||
1275 | FILE_SHARE_READ|FILE_SHARE_WRITE, | ||
1276 | NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL); | ||
1277 | #endif | ||
1278 | |||
1279 | if (isinvalidhandle(handle)) return false; | ||
1280 | // cout << "Trying to enable header mode with file " << headerfilename << endl; | ||
1281 | hd24header=handle; | ||
1282 | this->headersectors=0; | ||
1283 | this->headersectors=getlastsectornum(hd24header)+1; | ||
1284 | // re-read disk info as number of projects etc can differ with header | ||
1285 | readsector(devhd24,1,sector_diskinfo); // fstfix follows | ||
1286 | fstfix (sector_diskinfo,512); | ||
1287 | |||
1288 | // cout << "headersectors=" << this->headersectors << "this=" <<this << endl; | ||
1289 | return true; | ||
1290 | } | ||
1291 | |||
1292 | void hd24fs::clearbuffer(unsigned char* buffer,unsigned int bytes) | ||
1293 | { | ||
1294 | /* clear buffer */ | ||
1295 | for (unsigned int i=0;i<bytes;i++) { | ||
1296 | buffer[i]=0; | ||
1297 | } | ||
1298 | return; | ||
1299 | } | ||
1300 | |||
1301 | void hd24fs::clearbuffer(unsigned char* buffer) | ||
1302 | { | ||
1303 | clearbuffer(buffer,512); | ||
1304 | } | ||
1305 | |||
1306 | |||
1307 | void hd24fs::cleardriveinfo(unsigned char* buffer) | ||
1308 | { | ||
1309 | clearbuffer(buffer); | ||
1310 | string drivename="Drive Name"; | ||
1311 | this->setname(buffer,drivename,DRIVEINFO_VOLUME_8,DRIVEINFO_VOLUME); | ||
1312 | return; | ||
1313 | } | ||
1314 | |||
1315 | void hd24fs::useinternalboot(unsigned char* buffer,__uint32 lastsector) | ||
1316 | { | ||
1317 | unsigned char internal_boot[136]= | ||
1318 | { | ||
1319 | 0x54,0x41,0x44,0x41,0x54,0x53,0x46,0x20, 0x20,0x30,0x31,0x31,0x33,0xcc,0xaa,0x55, | ||
1320 | 0x80,0x04,0x00,0x00,0x02,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, | ||
1321 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00, | ||
1322 | 0x02,0x00,0x00,0x00,0x03,0x00,0x00,0x00, 0x05,0x00,0x00,0x00,0x0f,0x00,0x00,0x00, | ||
1323 | 0x2f,0x04,0x00,0x00,0x00,0x00,0x00,0x00, 0x14,0x00,0x00,0x00,0x01,0x00,0x00,0x00, | ||
1324 | 0x63,0x00,0x00,0x00,0x63,0x00,0x00,0x00, 0x77,0x00,0x00,0x00,0x02,0x00,0x00,0x00, | ||
1325 | 0x05,0x00,0x00,0x00,0x07,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x49,0x26,0x00,0x00, | ||
1326 | 0x76,0x0c,0x01,0x00,0x80,0x8b,0x12,0x00, 0x1f,0x04,0x00,0x00,0xf6,0x97,0x13,0x00, | ||
1327 | 0x14,0x89,0xb4,0x04,0x7f,0x2d,0xc9,0x04 | ||
1328 | }; | ||
1329 | |||
1330 | clearbuffer(buffer); | ||
1331 | |||
1332 | /* fill buffer with default boot info */ | ||
1333 | for (unsigned int i=0;i<sizeof(internal_boot);i++) { | ||
1334 | buffer[i]=internal_boot[i]; | ||
1335 | } | ||
1336 | |||
1337 | /* If a specific FS size (in sectors) was given, update boot info | ||
1338 | to match that size */ | ||
1339 | if (lastsector!=0) | ||
1340 | { | ||
1341 | #if (HD24FSDEBUG_QUICKFORMAT==1) | ||
1342 | cout << "Calculating number of clusters on the drive" << endl; | ||
1343 | #endif | ||
1344 | fstfix(buffer,512); // convert into editable format | ||
1345 | |||
1346 | Convert::setint32(buffer,FSINFO_LAST_SECTOR,lastsector); | ||
1347 | #if (HD24FSDEBUG_QUICKFORMAT==1) | ||
1348 | cout << "Last sector=" << lastsector << endl; | ||
1349 | #endif | ||
1350 | // allocatable sectors=total sectors-(2*fs sectors+undo area) | ||
1351 | // tot secs-0x14a46b | ||
1352 | |||
1353 | __uint32 allocatablesectors=lastsector-0x14a46b; | ||
1354 | #if (HD24FSDEBUG_QUICKFORMAT==1) | ||
1355 | cout << "# allocatable sectors=" << allocatablesectors << endl; | ||
1356 | #endif | ||
1357 | Convert::setint32(buffer,FSINFO_ALLOCATABLE_SECTORCOUNT,allocatablesectors); | ||
1358 | |||
1359 | // (15 sectors of drive usage info=((15*512)-8)*8 bits | ||
1360 | // | ||
1361 | __uint32 maxclusters=((15 /*sectors of alloc info*/ | ||
1362 | *512 /*bytes*/) | ||
1363 | -8 /* checksum bytes */) | ||
1364 | *8 /* bits per byte */; | ||
1365 | // represents ~ 61376 allocatable clusters | ||
1366 | #if (HD24FSDEBUG_QUICKFORMAT==1) | ||
1367 | cout << "max # of clusters=" << maxclusters << endl; | ||
1368 | #endif | ||
1369 | __uint32 allocatableaudioblocks=(allocatablesectors - (allocatablesectors%0x480))/0x480; | ||
1370 | #if (HD24FSDEBUG_QUICKFORMAT==1) | ||
1371 | cout << "allocatable audio blocks=" << allocatableaudioblocks << endl; | ||
1372 | #endif | ||
1373 | // given the maximum number of clusters | ||
1374 | // and the total number of allocatable audio blocks, | ||
1375 | // we must decide on the number of audio blocks per cluster. | ||
1376 | __uint32 rest=0; | ||
1377 | if ((allocatableaudioblocks%maxclusters)>0) rest++; | ||
1378 | __uint32 blockspercluster=rest+((allocatableaudioblocks-(allocatableaudioblocks%maxclusters))/maxclusters); | ||
1379 | #if (HD24FSDEBUG_QUICKFORMAT==1) | ||
1380 | cout << "blocks per cluster="<<blockspercluster<< endl; | ||
1381 | #endif | ||
1382 | Convert::setint32(buffer,FSINFO_AUDIOBLOCKS_PER_CLUSTER,blockspercluster); | ||
1383 | |||
1384 | // offset 0x14h: number of audio blocks per cluster | ||
1385 | __uint32 allocatableclusters=(allocatableaudioblocks-(allocatableaudioblocks%blockspercluster))/blockspercluster; | ||
1386 | Convert::setint32(buffer,FSINFO_FREE_CLUSTERS_ON_DISK,allocatableclusters); | ||
1387 | #if (HD24FSDEBUG_QUICKFORMAT==1) | ||
1388 | cout << "allocatableclusters="<<allocatableclusters<< endl; | ||
1389 | #endif | ||
1390 | fstfix(buffer,512); // convert back into native format | ||
1391 | } | ||
1392 | |||
1393 | /* Calculate the proper checksum for the bootinfo */ | ||
1394 | setsectorchecksum(buffer, | ||
1395 | 0 /* startoffset */, | ||
1396 | 0 /* sector */, | ||
1397 | 1 /*sectorcount */ | ||
1398 | ); | ||
1399 | return; | ||
1400 | } | ||
1401 | |||
1402 | unsigned char* hd24fs::readbootinfo() | ||
1403 | { | ||
1404 | // read boot info | ||
1405 | |||
1406 | if (sector_boot==NULL) | ||
1407 | { | ||
1408 | #if (HD24FSDEBUG_QUICKFORMAT==1) | ||
1409 | cout << "Malloc space for bootsector" << endl; | ||
1410 | #endif | ||
1411 | sector_boot=(unsigned char *)memutils::mymalloc("readbootinfo",1024,1); | ||
1412 | } | ||
1413 | |||
1414 | if (sector_boot!=NULL) | ||
1415 | { | ||
1416 | #if (HD24FSDEBUG_QUICKFORMAT==1) | ||
1417 | cout << "Malloc space for bootsector succeeded" << endl; | ||
1418 | cout << "forcemode=" << forcemode << endl; | ||
1419 | #endif | ||
1420 | if (formatting||(!forcemode)) { | ||
1421 | #if (HD24FSDEBUG_QUICKFORMAT==1) | ||
1422 | cout << "Reading sector (From disk)" << endl; | ||
1423 | #endif | ||
1424 | readsector(devhd24,0,sector_boot); | ||
1425 | } else { | ||
1426 | #if (HD24FSDEBUG_QUICKFORMAT==1) | ||
1427 | cout << "Using internal boot." << endl; | ||
1428 | #endif | ||
1429 | useinternalboot(sector_boot,0); | ||
1430 | } | ||
1431 | fstfix(sector_boot,512); | ||
1432 | } else { | ||
1433 | #if (HD24FSDEBUG_QUICKFORMAT==1) | ||
1434 | cout << "Malloc space for bootsector failed" << endl; | ||
1435 | #endif | ||
1436 | } | ||
1437 | #if (HD24FSDEBUG_QUICKFORMAT==1) | ||
1438 | dumpsector((const char*)sector_boot); | ||
1439 | #endif | ||
1440 | return sector_boot; | ||
1441 | } | ||
1442 | |||
1443 | unsigned char* hd24fs::readdriveusageinfo() | ||
1444 | { | ||
1445 | #if (HD24FSDEBUG==1)|| (HD24FSDEBUG_QUICKFORMAT==1) | ||
1446 | cout << "hd24fs::readdriveusageinfo()" << endl; | ||
1447 | #endif | ||
1448 | |||
1449 | // read file allocation table/disk usage table | ||
1450 | unsigned int driveusagecount=driveusagesectorcount(); | ||
1451 | if (sectors_driveusage==NULL) | ||
1452 | { | ||
1453 | |||
1454 | sectors_driveusage=(unsigned char *)memutils::mymalloc("readdriveusageinfo/sectors_driveusage",512*(driveusagecount+1),1); | ||
1455 | } | ||
1456 | //cout << "ptr=" << sectors_driveusage << endl; | ||
1457 | if (sectors_driveusage!=NULL) | ||
1458 | { | ||
1459 | #if (HD24FSDEBUG_QUICKFORMAT==1) | ||
1460 | cout << "hd24fs::readdriveusageinfo() reading " | ||
1461 | << driveusagecount << "sectors into buffer at " | ||
1462 | << §ors_driveusage << endl; | ||
1463 | #endif | ||
1464 | readsectors(devhd24,driveusagefirstsector(),sectors_driveusage,driveusagecount); | ||
1465 | fstfix(sectors_driveusage,512*driveusagecount); | ||
1466 | |||
1467 | } | ||
1468 | #if (HD24FSDEBUG_QUICKFORMAT==1) | ||
1469 | cout << "Dumping newly read sector to screen:" << endl ; | ||
1470 | dumpsector((const char*)sectors_driveusage); | ||
1471 | #endif | ||
1472 | return sectors_driveusage; | ||
1473 | } | ||
1474 | |||
1475 | unsigned char* hd24fs::resetsongusage() | ||
1476 | { | ||
1477 | // Reset song usage table. First we occupy all of it; | ||
1478 | // then we make only accessible entries available. | ||
1479 | if (sectors_songusage==NULL) | ||
1480 | { | ||
1481 | sectors_songusage=(unsigned char *)memutils::mymalloc("resetsongusage",512*3,1); | ||
1482 | if (sectors_songusage==NULL) | ||
1483 | { | ||
1484 | return NULL; | ||
1485 | } | ||
1486 | } | ||
1487 | |||
1488 | if (sectors_songusage!=NULL) | ||
1489 | { | ||
1490 | for (int i=0;i<512*3;i++) | ||
1491 | { | ||
1492 | sectors_songusage[i]=0xff; | ||
1493 | } | ||
1494 | } | ||
1495 | |||
1496 | __uint32 i; | ||
1497 | // table is initialized, now populate it. | ||
1498 | __uint32 maxprojs=this->maxprojects(); | ||
1499 | __uint32 maxsongcount=this->maxsongsperproject(); | ||
1500 | __uint32 totentries=maxprojs*maxsongcount; // 99 songs, 99 projects | ||
1501 | #if (HD24FSDEBUG==1) | ||
1502 | cout << "Clear song usage table..."<< endl; | ||
1503 | cout << "this=" << this << endl; | ||
1504 | #endif | ||
1505 | for (i=0;i<totentries;i++) { | ||
1506 | disablebit(i,sectors_songusage); | ||
1507 | // this is based on song sectors. | ||
1508 | // That is, entry 0=sec 0x77, | ||
1509 | // entry 1=sec 0x77+7, etc. | ||
1510 | } | ||
1511 | #if (HD24FSDEBUG==1) | ||
1512 | cout << "Usage table cleared." << endl; | ||
1513 | #endif | ||
1514 | return sectors_songusage; | ||
1515 | } | ||
1516 | |||
1517 | unsigned char* hd24fs::resetdriveusage() | ||
1518 | { | ||
1519 | #if (HD24FSDEBUG==1)||(HD24FSDEBUG_QUICKFORMAT==1) | ||
1520 | cout << "hd24fs::resetdriveusage()" << endl; | ||
1521 | #endif | ||
1522 | // Reset drive usage table. First we occupy all of it; | ||
1523 | // then we make only accessible entries available. | ||
1524 | |||
1525 | if (this->sectors_driveusage==NULL) | ||
1526 | { | ||
1527 | unsigned char* du=(unsigned char *)memutils::mymalloc("resetdriveusage/sectors_driveusage",512*15,1); | ||
1528 | sectors_driveusage=du; | ||
1529 | if (this->sectors_driveusage==NULL) | ||
1530 | { | ||
1531 | return NULL; | ||
1532 | } | ||
1533 | } | ||
1534 | |||
1535 | for (int i=0;i<512*15;i++) | ||
1536 | { | ||
1537 | sectors_driveusage[i]=0xff; | ||
1538 | } | ||
1539 | |||
1540 | if (formatting||(sector_boot==NULL) ) | ||
1541 | { | ||
1542 | #if (HD24FSDEBUG_QUICKFORMAT==1) | ||
1543 | cout << "hd24fs::resetdriveusage() - reloading boot info " << endl; | ||
1544 | #endif | ||
1545 | |||
1546 | this->readbootinfo(); | ||
1547 | } else { | ||
1548 | #if (HD24FSDEBUG_QUICKFORMAT==1) | ||
1549 | cout << "hd24fs::resetdriveusage() - using current (not reloading) boot info " << endl; | ||
1550 | #endif | ||
1551 | |||
1552 | } | ||
1553 | |||
1554 | __uint32 i; | ||
1555 | // table is initialized, now populate it. | ||
1556 | __uint32 totentries=Convert::getint32(sector_boot,FSINFO_FREE_CLUSTERS_ON_DISK); | ||
1557 | #if (HD24FSDEBUG_QUICKFORMAT==1) | ||
1558 | cout << "According to superblock, free clusters on disk=" << totentries << endl; | ||
1559 | dumpsector((const char*)sector_boot); | ||
1560 | #endif | ||
1561 | #if (HD24FSDEBUG_QUICKFORMAT==1) | ||
1562 | cout << "before reset, drive usage looks as follows: "<< endl; | ||
1563 | dumpsector((const char*)sectors_driveusage); | ||
1564 | #endif | ||
1565 | for (i=0;i<totentries;i++) { | ||
1566 | disablebit(i,sectors_driveusage); | ||
1567 | } | ||
1568 | #if (HD24FSDEBUG_QUICKFORMAT==1) | ||
1569 | cout << "after reset, drive usage looks as follows: "<< endl; | ||
1570 | dumpsector((const char*)sectors_driveusage); | ||
1571 | #endif | ||
1572 | |||
1573 | #if (HD24FSDEBUG==1) | ||
1574 | cout << "Drive usage table cleared." << endl; | ||
1575 | #endif | ||
1576 | return sectors_driveusage; | ||
1577 | } | ||
1578 | |||
1579 | unsigned char* hd24fs::calcsongusage() | ||
1580 | { | ||
1581 | resetsongusage(); | ||
1582 | |||
1583 | hd24project* currproj=NULL; | ||
1584 | __uint32 projcount=projectcount(); | ||
1585 | __uint32 i; | ||
1586 | __uint32 j; | ||
1587 | for (i=1; i<=projcount;i++) | ||
1588 | { | ||
1589 | if (currproj!=NULL) | ||
1590 | { | ||
1591 | delete(currproj); | ||
1592 | currproj=NULL; | ||
1593 | } | ||
1594 | currproj=getproject(i); | ||
1595 | if (currproj==NULL) | ||
1596 | { | ||
1597 | continue; | ||
1598 | } | ||
1599 | |||
1600 | // currproj!=NULL. | ||
1601 | __uint32 currsongcount=currproj->songcount(); | ||
1602 | for (j=1; j<=currsongcount;j++) | ||
1603 | { | ||
1604 | // get song sector info. | ||
1605 | __uint32 songsector = currproj->getsongsectornum(j); | ||
1606 | if (songsector==0) | ||
1607 | { | ||
1608 | // song at given entry is not in use | ||
1609 | // in this project, no need to mark it as used. | ||
1610 | continue; | ||
1611 | } | ||
1612 | |||
1613 | // mark the song used based on its entry number | ||
1614 | // (calculated from the sector where it lives) | ||
1615 | __uint32 songentry=songsector2entry(songsector); | ||
1616 | if (songentry!=INVALID_SONGENTRY) | ||
1617 | { | ||
1618 | enablebit(songentry,sectors_songusage); | ||
1619 | } | ||
1620 | } | ||
1621 | |||
1622 | if (currproj!=NULL) | ||
1623 | { | ||
1624 | delete(currproj); | ||
1625 | currproj=NULL; | ||
1626 | } | ||
1627 | } | ||
1628 | return sectors_songusage; | ||
1629 | } | ||
1630 | |||
1631 | void hd24fs::refreshsongusage() | ||
1632 | { | ||
1633 | unsigned char* songusage=calcsongusage(); | ||
1634 | __uint32 sectornum=2; /* TODO: get from fs */ | ||
1635 | __uint32 sectorcount=3; /* TODO: get from fs */ | ||
1636 | fstfix(songusage,sectorcount*512); | ||
1637 | setsectorchecksum(songusage, | ||
1638 | 0 /* startoffset */, | ||
1639 | sectornum /* sector */, | ||
1640 | sectorcount /*sectorcount */ | ||
1641 | ); | ||
1642 | this->writesectors(this->devhd24, | ||
1643 | sectornum, | ||
1644 | songusage, | ||
1645 | sectorcount); | ||
1646 | fstfix(songusage,sectorcount*512); | ||
1647 | |||
1648 | /* this also implies we need to update the superblock | ||
1649 | with the current song count */ | ||
1650 | __uint32 songcount=0; | ||
1651 | for (int i=0;i<99*99;i++) { | ||
1652 | if (!(isbitzero(i,songusage))) | ||
1653 | { | ||
1654 | songcount++; | ||
1655 | } | ||
1656 | }; | ||
1657 | songsondisk(songcount); | ||
1658 | fstfix(sector_boot,512); | ||
1659 | setsectorchecksum(sector_boot, | ||
1660 | 0 /* startoffset */, | ||
1661 | 0 /* sector */, | ||
1662 | 1 /*sectorcount */); | ||
1663 | this->writesectors(this->devhd24, | ||
1664 | 0, | ||
1665 | sector_boot, | ||
1666 | 1); | ||
1667 | fstfix(sector_boot,512); | ||
1668 | return; | ||
1669 | } | ||
1670 | |||
1671 | unsigned char* hd24fs::getsector_diskinfo() | ||
1672 | { | ||
1673 | getsector_bootinfo(); | ||
1674 | unsigned char* targetbuf=sector_diskinfo; | ||
1675 | if (/*formatting||*/(sector_diskinfo==NULL) ) | ||
1676 | { | ||
1677 | targetbuf=readdiskinfo(); | ||
1678 | } | ||
1679 | return sector_diskinfo; | ||
1680 | } | ||
1681 | |||
1682 | unsigned char* hd24fs::getsector_bootinfo() | ||
1683 | { | ||
1684 | unsigned char* targetbuf=sector_boot; | ||
1685 | if (/*formatting||*/(sector_boot==NULL) ) | ||
1686 | { | ||
1687 | #if (HD24FSDEBUG_QUICKFORMAT==1) | ||
1688 | cout << "Re-reading bootinfo now." << endl; | ||
1689 | #endif | ||
1690 | targetbuf=readbootinfo(); | ||
1691 | } | ||
1692 | return targetbuf; | ||
1693 | } | ||
1694 | |||
1695 | unsigned char* hd24fs::getsectors_driveusage() | ||
1696 | { | ||
1697 | #if (HD24FSDEBUG_QUICKFORMAT==1) | ||
1698 | cout << "hd24fs::getsectors_driveusage()" << endl; | ||
1699 | #endif | ||
1700 | |||
1701 | readbootinfo(); | ||
1702 | if (sectors_driveusage==NULL) | ||
1703 | { | ||
1704 | sectors_driveusage=readdriveusageinfo(); | ||
1705 | } | ||
1706 | return sectors_driveusage; | ||
1707 | } | ||
1708 | |||
1709 | unsigned char* hd24fs::getcopyofusagetable() | ||
1710 | { | ||
1711 | unsigned char* copyusagetable=(unsigned char*)memutils::mymalloc("copyusagetable",15*512,1); | ||
1712 | if (copyusagetable==NULL) | ||
1713 | { | ||
1714 | /* Out of memory */ | ||
1715 | return NULL; | ||
1716 | } | ||
1717 | |||
1718 | // copy current drive usage table to a copy; | ||
1719 | readdriveusageinfo(); | ||
1720 | int i; | ||
1721 | for (i=0;i<(512*15);i++) { | ||
1722 | copyusagetable[i]=sectors_driveusage[i]; | ||
1723 | } | ||
1724 | return copyusagetable; | ||
1725 | } | ||
1726 | |||
1727 | string* hd24fs::volumename() | ||
1728 | { | ||
1729 | if (!(isOpen())) | ||
1730 | { | ||
1731 | return new string(""); | ||
1732 | } | ||
1733 | getsector_diskinfo(); | ||
1734 | return Convert::readstring(sector_diskinfo,DRIVEINFO_VOLUME,64); | ||
1735 | } | ||
1736 | |||
1737 | void hd24fs::setvolumename(string newname) | ||
1738 | { | ||
1739 | if (sector_diskinfo==NULL) | ||
1740 | { | ||
1741 | readdiskinfo(); | ||
1742 | } | ||
1743 | this->setname(sector_diskinfo,newname,DRIVEINFO_VOLUME_8,DRIVEINFO_VOLUME); | ||
1744 | return; | ||
1745 | } | ||
1746 | |||
1747 | unsigned long hd24fs::driveusagesectorcount() | ||
1748 | { | ||
1749 | if (!(isOpen())) | ||
1750 | { | ||
1751 | cout << "FS not open!"; | ||
1752 | return 0; | ||
1753 | } | ||
1754 | #if (HD24FSDEBUG_QUICKFORMAT==1) | ||
1755 | cout << "Figuring out number of sectors used for drive usage" | ||
1756 | << endl; | ||
1757 | #endif | ||
1758 | |||
1759 | getsector_bootinfo(); | ||
1760 | return Convert::getint32(sector_boot,FSINFO_NUMSECTORS_DRIVEUSAGE); | ||
1761 | } | ||
1762 | |||
1763 | unsigned long hd24fs::clustercount() | ||
1764 | { | ||
1765 | /* | ||
1766 | Clustercount= | ||
1767 | (number of allocatable sectors on disk)/ | ||
1768 | ((sectors per audioblock)*(audioblocks per cluster)) | ||
1769 | */ | ||
1770 | if (!(isOpen())) | ||
1771 | { | ||
1772 | return 0; | ||
1773 | } | ||
1774 | getsector_bootinfo(); | ||
1775 | __uint32 allocatablesectorcount= | ||
1776 | Convert::getint32(sector_boot,FSINFO_ALLOCATABLE_SECTORCOUNT); | ||
1777 | __uint32 audioblocksize= | ||
1778 | Convert::getint32(sector_boot,FSINFO_BLOCKSIZE_IN_SECTORS); | ||
1779 | __uint32 clustersize= | ||
1780 | Convert::getint32(sector_boot,FSINFO_AUDIOBLOCKS_PER_CLUSTER) | ||
1781 | *audioblocksize; | ||
1782 | |||
1783 | allocatablesectorcount-=(allocatablesectorcount%clustersize); | ||
1784 | return allocatablesectorcount/clustersize; | ||
1785 | } | ||
1786 | |||
1787 | void hd24fs::dumpclusterusage(unsigned char* usagebuffer) | ||
1788 | { | ||
1789 | if (!(isOpen())) | ||
1790 | { | ||
1791 | return; | ||
1792 | } | ||
1793 | __uint32 clusters=clustercount(); | ||
1794 | for (__uint32 i=0;i<clusters;i++) { | ||
1795 | if (isfreecluster(i,usagebuffer)) { | ||
1796 | cout << "0"; | ||
1797 | } else { | ||
1798 | cout << "1"; | ||
1799 | } | ||
1800 | } | ||
1801 | cout <<endl; | ||
1802 | return; | ||
1803 | } | ||
1804 | |||
1805 | void hd24fs::dumpclusterusage2(unsigned char* usagebuffer) | ||
1806 | { | ||
1807 | __uint32 clusters=clustercount(); | ||
1808 | __uint32 currpos=0; | ||
1809 | cout << "DumpClusterUsage2" << endl; | ||
1810 | while (currpos<clusters) { | ||
1811 | __uint32 blockstart=currpos; | ||
1812 | while (isfreecluster(blockstart,usagebuffer) && (blockstart<clusters)) { | ||
1813 | blockstart++; | ||
1814 | } | ||
1815 | // cout << "Block starts at cluster " <<blockstart << endl; | ||
1816 | if (blockstart==clusters) { | ||
1817 | break; | ||
1818 | } | ||
1819 | |||
1820 | // blockstart now points to a nonfree cluster | ||
1821 | __uint32 blockend=blockstart; | ||
1822 | while (!isfreecluster(blockend,usagebuffer) && (blockend<clusters)) { | ||
1823 | blockend++; | ||
1824 | } | ||
1825 | // blockend now points to a free cluster | ||
1826 | currpos=blockend; | ||
1827 | __uint32 blocklen=blockend-blockstart; | ||
1828 | printf("%x %x\n",(unsigned int) cluster2sector(blockstart),(unsigned int)( getblockspercluster()*blocklen )); | ||
1829 | } | ||
1830 | } | ||
1831 | |||
1832 | unsigned long hd24fs::driveusagefirstsector() | ||
1833 | { | ||
1834 | if (!(isOpen())) | ||
1835 | { | ||
1836 | return 0; | ||
1837 | } | ||
1838 | getsector_bootinfo(); | ||
1839 | |||
1840 | return Convert::getint32(sector_boot,FSINFO_STARTSECTOR_DRIVEUSAGE); | ||
1841 | } | ||
1842 | |||
1843 | unsigned char* hd24fs::findorphanclusters() | ||
1844 | { | ||
1845 | if (!(isOpen())) | ||
1846 | { | ||
1847 | return NULL; | ||
1848 | } | ||
1849 | __uint32 driveusagecount=driveusagesectorcount(); | ||
1850 | getsectors_driveusage(); | ||
1851 | int numprojs=projectcount(); | ||
1852 | |||
1853 | if (sectors_orphan==NULL) { | ||
1854 | // only allocate once (free on object destruct) | ||
1855 | sectors_orphan=(unsigned char *)memutils::mymalloc("findorphanclusters",512*(driveusagecount+1),1); | ||
1856 | } | ||
1857 | readsectors(devhd24,driveusagefirstsector(),sectors_orphan,driveusagecount); | ||
1858 | fstfix(sectors_orphan,512*driveusagecount); | ||
1859 | |||
1860 | for (int proj=1; proj<=numprojs; proj++) { | ||
1861 | hd24project* currproj=this->getproject(proj); | ||
1862 | int numsongs=currproj->songcount(); | ||
1863 | for (int song=1; song<=numsongs; song++) { | ||
1864 | hd24song* currsong=currproj->getsong(song); | ||
1865 | if (currsong==NULL) continue; | ||
1866 | currsong->unmark_used_clusters(sectors_orphan); | ||
1867 | delete currsong; | ||
1868 | } | ||
1869 | if (currproj!=NULL) { | ||
1870 | delete currproj; | ||
1871 | currproj=NULL; | ||
1872 | } | ||
1873 | } | ||
1874 | return sectors_orphan; | ||
1875 | } | ||
1876 | |||
1877 | bool hd24fs::isbitzero(unsigned long i,unsigned char* usagebuffer) | ||
1878 | { | ||
1879 | int bitnum=i%32; | ||
1880 | i-=bitnum; | ||
1881 | i/=32; // i now is word num | ||
1882 | i*=4; // i now is offset | ||
1883 | __uint32 getword=Convert::getint32(usagebuffer,i); | ||
1884 | __uint32 mask=1; | ||
1885 | #if (HD24FSDEBUG_BITSET==1) | ||
1886 | cout << "bitnum=" << bitnum << " "; | ||
1887 | #endif | ||
1888 | mask=mask<<bitnum; | ||
1889 | __uint32 bitval=(getword & mask); | ||
1890 | #if (HD24FSDEBUG_BITSET==1) | ||
1891 | cout << "bitval=" << bitval << endl; | ||
1892 | #endif | ||
1893 | if (bitval == 0) return true; | ||
1894 | return false; | ||
1895 | } | ||
1896 | |||
1897 | void hd24fs::enablebit(__uint32 ibitnum,unsigned char* usagebuffer) | ||
1898 | { | ||
1899 | #if (HD24FSDEBUG_BITSET==1) | ||
1900 | cout << "enable bit " << ibitnum << endl; | ||
1901 | #endif | ||
1902 | int bitnum=ibitnum%32; | ||
1903 | ibitnum-=bitnum; | ||
1904 | ibitnum/=32; // i now is word num | ||
1905 | ibitnum*=4; // i now is byte offset of word | ||
1906 | __uint32 getword=Convert::getint32(usagebuffer,ibitnum); | ||
1907 | __uint32 mask=1; | ||
1908 | mask=mask<<bitnum; | ||
1909 | #if (HD24FSDEBUG_BITSET==1) | ||
1910 | cout << "getword=" << getword << "mask=" << mask << endl; | ||
1911 | #endif | ||
1912 | getword=getword|mask; | ||
1913 | Convert::setint32(usagebuffer,ibitnum,getword); | ||
1914 | } | ||
1915 | |||
1916 | void hd24fs::disablebit(__uint32 ibitnum,unsigned char* usagebuffer) | ||
1917 | { | ||
1918 | #if (HD24FSDEBUG_BITSET==1) | ||
1919 | cout << "disable bit " << ibitnum << endl; | ||
1920 | #endif | ||
1921 | int bitnum=ibitnum%32; | ||
1922 | ibitnum-=bitnum; | ||
1923 | ibitnum/=32; // i now is word num | ||
1924 | ibitnum*=4; // i now is offset | ||
1925 | __uint32 getword=Convert::getint32(usagebuffer,ibitnum); | ||
1926 | __uint32 mask=1; | ||
1927 | mask=mask<<bitnum; | ||
1928 | #if (HD24FSDEBUG_BITSET==1) | ||
1929 | cout << "getword=" << getword << "mask=" << mask << endl; | ||
1930 | #endif | ||
1931 | getword=getword& (0xFFFFFFFF ^ mask); | ||
1932 | #if (HD24FSDEBUG_BITSET==1) | ||
1933 | cout << "new getword=" << getword << endl; | ||
1934 | #endif | ||
1935 | Convert::setint32(usagebuffer,ibitnum,getword); | ||
1936 | } | ||
1937 | |||
1938 | bool hd24fs::isfreecluster(unsigned long i,unsigned char* usagebuffer) | ||
1939 | { | ||
1940 | return isbitzero(i,usagebuffer); | ||
1941 | } | ||
1942 | |||
1943 | void hd24fs::allocatecluster(__uint32 clusternum,unsigned char* usagebuffer) | ||
1944 | { | ||
1945 | enablebit(clusternum,usagebuffer); | ||
1946 | } | ||
1947 | |||
1948 | void hd24fs::freecluster(__uint32 clusternum,unsigned char* usagebuffer) | ||
1949 | { | ||
1950 | disablebit(clusternum,usagebuffer); | ||
1951 | } | ||
1952 | void hd24fs::allocatecluster(__uint32 clusternum) | ||
1953 | { | ||
1954 | allocatecluster(clusternum,sectors_driveusage); | ||
1955 | } | ||
1956 | |||
1957 | void hd24fs::freecluster(__uint32 clusternum) | ||
1958 | { | ||
1959 | freecluster(clusternum,sectors_driveusage); | ||
1960 | } | ||
1961 | |||
1962 | unsigned long hd24fs::freeclustercount() | ||
1963 | { | ||
1964 | if (!(isOpen())) | ||
1965 | { | ||
1966 | return 0; | ||
1967 | } | ||
1968 | #if (HD24FSDEBUG_QUICKFORMAT==1) | ||
1969 | cout << "hd24fs::freeclustercount()" << endl; | ||
1970 | #endif | ||
1971 | |||
1972 | sectors_driveusage=getsectors_driveusage(); | ||
1973 | |||
1974 | if (sectors_driveusage==NULL) | ||
1975 | { | ||
1976 | return 0; // cannot get driveusage sectors, 0 clusters free. | ||
1977 | } | ||
1978 | unsigned long i=0; | ||
1979 | __uint32 fsc=driveusagesectorcount(); | ||
1980 | |||
1981 | if (fsc>0xFF) return 0; | ||
1982 | #if (HD24FSDEBUG_QUICKFORMAT==1) | ||
1983 | cout << "Sectors used for drive usage=" << fsc << endl; | ||
1984 | #endif | ||
1985 | __uint32 clusters=((fsc /*sectors of alloc info*/ | ||
1986 | *512 /*bytes*/) | ||
1987 | -8 /* checksum bytes */) | ||
1988 | *8 /* bits per byte */; | ||
1989 | //unsigned long clusters=((512*fsc-1)+504)*8; | ||
1990 | #if (HD24FSDEBUG_QUICKFORMAT==1) | ||
1991 | cout << "Total clusters=" << clusters << endl; | ||
1992 | #endif | ||
1993 | |||
1994 | unsigned long freeclusters=0; | ||
1995 | for (i=0;i<clusters;i++) { | ||
1996 | if (isfreecluster(i,sectors_driveusage)) | ||
1997 | { | ||
1998 | #if (HD24FSDEBUG_QUICKFORMAT==1) | ||
1999 | cout << "Cluster " << i << " is free" << endl; | ||
2000 | #endif | ||
2001 | freeclusters++; | ||
2002 | } | ||
2003 | } | ||
2004 | return freeclusters; | ||
2005 | } | ||
2006 | |||
2007 | string* hd24fs::freespace(unsigned long rate,unsigned long tracks) | ||
2008 | { | ||
2009 | if (!(isOpen())) | ||
2010 | { | ||
2011 | return new string(""); | ||
2012 | } | ||
2013 | |||
2014 | unsigned long freeclusters=freeclustercount(); | ||
2015 | #if (HD24FSDEBUG_QUICKFORMAT==1) | ||
2016 | cout << "free clusters=" << freeclusters << endl; | ||
2017 | #endif | ||
2018 | __uint64 freesectors=freeclusters*getblocksizeinsectors()*getblockspercluster(); | ||
2019 | #if (HD24FSDEBUG_QUICKFORMAT==1) | ||
2020 | cout << "free sectors=" << freesectors << endl; | ||
2021 | #endif | ||
2022 | __uint64 freebytes=freesectors*SECTORSIZE; | ||
2023 | #if (HD24FSDEBUG_QUICKFORMAT==1) | ||
2024 | cout << "free bytes=" << freesectors << endl; | ||
2025 | #endif | ||
2026 | __uint64 freesamples=(__uint64)(freebytes/3); | ||
2027 | #if (HD24FSDEBUG_QUICKFORMAT==1) | ||
2028 | cout << "free samples=" << freesamples << endl; | ||
2029 | #endif | ||
2030 | __uint64 freeseconds=(__uint64)(freesamples/rate/tracks); | ||
2031 | unsigned long freehours=(freeseconds-(freeseconds%3600))/3600; | ||
2032 | freeseconds-=(freehours*3600); | ||
2033 | unsigned long freeminutes=(freeseconds-(freeseconds%60))/60; | ||
2034 | freeseconds-=(freeminutes*60); | ||
2035 | string* newst=Convert::int2str(freehours); | ||
2036 | *newst+=" hr "; | ||
2037 | string* freemins=Convert::int2str(freeminutes,2,"0"); | ||
2038 | *newst+=*freemins; | ||
2039 | delete freemins; | ||
2040 | *newst+=" min "; | ||
2041 | string* freesecs=Convert::int2str(freeseconds,2,"0"); | ||
2042 | *newst+=*freesecs; | ||
2043 | delete freesecs; | ||
2044 | *newst+=" sec "; | ||
2045 | return newst; // throw exception? | ||
2046 | } | ||
2047 | |||
2048 | string* hd24fs::version() | ||
2049 | { | ||
2050 | if (!(isOpen())) | ||
2051 | { | ||
2052 | return new string(""); | ||
2053 | } | ||
2054 | getsector_bootinfo(); | ||
2055 | string* newst=Convert::readstring(sector_boot,FSINFO_VERSION_MAJOR,1); | ||
2056 | *newst+="."; | ||
2057 | string* dummy=Convert::readstring(sector_boot,FSINFO_VERSION_MINOR,2); | ||
2058 | *newst+=*dummy; | ||
2059 | delete dummy; | ||
2060 | return newst; | ||
2061 | } | ||
2062 | |||
2063 | unsigned long hd24fs::maxprojects() | ||
2064 | { | ||
2065 | if (!(isOpen())) | ||
2066 | { | ||
2067 | return 0; | ||
2068 | } | ||
2069 | getsector_bootinfo(); | ||
2070 | unsigned long maxprojs=Convert::getint32(sector_boot,FSINFO_MAXPROJECTS); | ||
2071 | if (maxprojs>99) { | ||
2072 | maxprojs=99; | ||
2073 | /* safety feature while no larger project | ||
2074 | counts are known to be valid; gives | ||
2075 | more stability when working with corrupt drives */ | ||
2076 | this->writeprotected=true; | ||
2077 | } | ||
2078 | return maxprojs; | ||
2079 | } | ||
2080 | |||
2081 | unsigned long hd24fs::getblocksizeinsectors() | ||
2082 | { | ||
2083 | if (!(isOpen())) | ||
2084 | { | ||
2085 | return 0; | ||
2086 | } | ||
2087 | getsector_bootinfo(); | ||
2088 | if (forcemode) { | ||
2089 | return 0x480; | ||
2090 | } | ||
2091 | unsigned long blocksize=Convert::getint32(sector_boot,FSINFO_BLOCKSIZE_IN_SECTORS); | ||
2092 | if (blocksize!=0x480) | ||
2093 | { | ||
2094 | this->writeprotected=true; | ||
2095 | } | ||
2096 | return blocksize; | ||
2097 | } | ||
2098 | |||
2099 | unsigned long hd24fs::getbytesperaudioblock() | ||
2100 | { | ||
2101 | return getblocksizeinsectors()*512; | ||
2102 | } | ||
2103 | |||
2104 | unsigned long hd24fs::getblockspercluster() | ||
2105 | { | ||
2106 | if (!(isOpen())) | ||
2107 | { | ||
2108 | return 0; | ||
2109 | } | ||
2110 | getsector_bootinfo(); | ||
2111 | unsigned long maxprojs=Convert::getint32(sector_boot,FSINFO_AUDIOBLOCKS_PER_CLUSTER); | ||
2112 | return maxprojs; | ||
2113 | } | ||
2114 | |||
2115 | unsigned long hd24fs::maxsongsperproject() | ||
2116 | { | ||
2117 | if (!(isOpen())) | ||
2118 | { | ||
2119 | return 0; | ||
2120 | } | ||
2121 | getsector_bootinfo(); | ||
2122 | unsigned long maxsongs=Convert::getint32(sector_boot,FSINFO_MAXSONGSPERPROJECT); | ||
2123 | return maxsongs; | ||
2124 | } | ||
2125 | |||
2126 | __uint32 hd24fs::getprojectsectornum(__uint32 i) | ||
2127 | { | ||
2128 | #if (HD24FSDEBUG==1) | ||
2129 | cout << "hd24fs::getprojectsectornum("<<i<<")"<< endl; | ||
2130 | #endif | ||
2131 | // 1-based project sectornum | ||
2132 | if (!(isOpen())) | ||
2133 | { | ||
2134 | return 0; | ||
2135 | } | ||
2136 | if (i<1) | ||
2137 | { | ||
2138 | return 0; | ||
2139 | } | ||
2140 | if (i>maxprojects()) | ||
2141 | { | ||
2142 | return 0; | ||
2143 | } | ||
2144 | getsector_diskinfo(); | ||
2145 | unsigned long projsec=Convert::getint32(sector_diskinfo, | ||
2146 | DRIVEINFO_PROJECTLIST+((i-1)*4)); | ||
2147 | |||
2148 | #if (HD24FSDEBUG==1) | ||
2149 | cout << "projsec = " << projsec << endl; | ||
2150 | #endif | ||
2151 | return projsec; | ||
2152 | } | ||
2153 | |||
2154 | void hd24fs::lastprojectid(signed long projectid) | ||
2155 | { | ||
2156 | if (!(isOpen())) | ||
2157 | { | ||
2158 | return; | ||
2159 | } | ||
2160 | getsector_diskinfo(); | ||
2161 | __uint32 lastprojsec=getprojectsectornum(projectid); | ||
2162 | if (lastprojsec==0) { | ||
2163 | return; | ||
2164 | } | ||
2165 | if (projectid==lastprojectid()) | ||
2166 | { | ||
2167 | // nothing changed- nothing to save | ||
2168 | return; | ||
2169 | } | ||
2170 | |||
2171 | Convert::setint32(sector_diskinfo,DRIVEINFO_LASTPROJ,lastprojsec); | ||
2172 | savedriveinfo(); | ||
2173 | return; | ||
2174 | } | ||
2175 | |||
2176 | signed long hd24fs::lastprojectid() | ||
2177 | { | ||
2178 | if (!(isOpen())) | ||
2179 | { | ||
2180 | return -1; | ||
2181 | } | ||
2182 | getsector_diskinfo(); | ||
2183 | unsigned long lastprojsec=Convert::getint32(sector_diskinfo,DRIVEINFO_LASTPROJ); | ||
2184 | if (lastprojsec==0) { | ||
2185 | // TODO: This differs from the real HD24 where even | ||
2186 | // on a freshly formatted drive there always is at least | ||
2187 | // one project. | ||
2188 | return -1; | ||
2189 | } | ||
2190 | int i; | ||
2191 | int maxprojs=maxprojects(); | ||
2192 | for (i=1;i<=maxprojs;i++) | ||
2193 | { | ||
2194 | unsigned long projsec=getprojectsectornum(i); | ||
2195 | |||
2196 | if (projsec==lastprojsec) | ||
2197 | { | ||
2198 | return i; | ||
2199 | } | ||
2200 | } | ||
2201 | // no default project. hm...... | ||
2202 | if (maxprojs>=1) { | ||
2203 | return 1; | ||
2204 | } | ||
2205 | return -1; | ||
2206 | } | ||
2207 | |||
2208 | __uint32 hd24fs::getunusedsongsector() | ||
2209 | { | ||
2210 | if (!(isOpen())) | ||
2211 | { | ||
2212 | return 0; // return 0- this is an invalid songsector | ||
2213 | // so error is detectable | ||
2214 | } | ||
2215 | |||
2216 | // generate an up-to-date song usage table. | ||
2217 | unsigned char* songusage=calcsongusage(); | ||
2218 | |||
2219 | int currsongentry=0; | ||
2220 | signed long foundentry=-1; | ||
2221 | int maxprojs=this->maxprojects(); | ||
2222 | int maxsongcount=this->maxsongsperproject(); | ||
2223 | int totentries=maxprojs*maxsongcount; // 99 songs, 99 projects | ||
2224 | while (currsongentry<totentries) // 99 sec, 99 proj | ||
2225 | { | ||
2226 | if (isbitzero(currsongentry,songusage)) { | ||
2227 | foundentry=currsongentry; | ||
2228 | break; | ||
2229 | } | ||
2230 | currsongentry++; | ||
2231 | } | ||
2232 | if (foundentry==-1) | ||
2233 | { | ||
2234 | return 0; | ||
2235 | } | ||
2236 | return songentry2sector(foundentry); | ||
2237 | } | ||
2238 | |||
2239 | void hd24fs::allocsongentry(unsigned long songentry) | ||
2240 | { | ||
2241 | enablebit(songentry,sectors_songusage); | ||
2242 | } | ||
2243 | |||
2244 | unsigned long hd24fs::projectcount() | ||
2245 | { | ||
2246 | if (!(isOpen())) | ||
2247 | { | ||
2248 | return 0; | ||
2249 | } | ||
2250 | getsector_diskinfo(); | ||
2251 | unsigned long lastprojsec=Convert::getint32(sector_diskinfo,DRIVEINFO_LASTPROJ); | ||
2252 | if (lastprojsec==0) | ||
2253 | { | ||
2254 | return 0; | ||
2255 | } | ||
2256 | __uint32 projcount=Convert::getint32(sector_diskinfo,DRIVEINFO_PROJECTCOUNT); | ||
2257 | if (projcount>maxprojects()) return maxprojects(); | ||
2258 | |||
2259 | return projcount; | ||
2260 | } | ||
2261 | |||
2262 | int hd24fs::mode() { | ||
2263 | return p_mode; | ||
2264 | } | ||
2265 | |||
2266 | hd24project* hd24fs::getproject(__sint32 projectid) | ||
2267 | { | ||
2268 | __uint32 projsec=getprojectsectornum(projectid); // 1-based | ||
2269 | if (projsec==0) { | ||
2270 | return NULL; | ||
2271 | } | ||
2272 | return new hd24project(this,projectid); | ||
2273 | } | ||
2274 | |||
2275 | hd24project* hd24fs::createproject(const char* projectname) | ||
2276 | { | ||
2277 | #if (HD24FSDEBUG==1) | ||
2278 | cout << "hd24fs::createproject(" << projectname << ")" << endl; | ||
2279 | // cout << "Driveusage before createproject=" << (int)(this->sectors_driveusage) << endl; | ||
2280 | #endif | ||
2281 | /* This creates a new project (with given project name) | ||
2282 | on the drive (if possible). | ||
2283 | NULL is returned when unsuccessful, a pointer to the | ||
2284 | project otherwise. | ||
2285 | */ | ||
2286 | #if (HD24FSDEBUG==1) | ||
2287 | cout << "hd24fs asked to create project " << projectname << endl; | ||
2288 | #endif | ||
2289 | int i; | ||
2290 | // find first project with project sector num 0! | ||
2291 | int maxprojs=maxprojects(); | ||
2292 | |||
2293 | getsector_bootinfo(); | ||
2294 | if (sector_boot==NULL) { | ||
2295 | // unknown cluster size. | ||
2296 | return 0; | ||
2297 | } | ||
2298 | __uint32 firstprojsec=Convert::getint32(sector_boot,FSINFO_FIRST_PROJECT_SECTOR); | ||
2299 | cout << "Firstprojsec="<< firstprojsec << endl; | ||
2300 | __uint32 secsperproj=Convert::getint32(sector_boot,FSINFO_SECTORS_PER_PROJECT); | ||
2301 | cout << "Sectors per project="<< secsperproj << endl; | ||
2302 | |||
2303 | // Let's calculate a list of unused project sectors | ||
2304 | char* projused=(char*)memutils::mymalloc("createproject",maxprojs,1); | ||
2305 | if (projused==NULL) { | ||
2306 | return 0; // out of memory | ||
2307 | } | ||
2308 | |||
2309 | for (i=0;i<maxprojs;i++) { | ||
2310 | projused[i]=0; | ||
2311 | } | ||
2312 | |||
2313 | for (i=1;i<=maxprojs;i++) { | ||
2314 | __uint32 projsec=getprojectsectornum(i); // 1-based | ||
2315 | if (projsec!=0) | ||
2316 | { | ||
2317 | /* projects do not necessarily have to | ||
2318 | be stored on disk in the same order | ||
2319 | as their project numbers- | ||
2320 | so project 1 can be at sector 0x15 | ||
2321 | while project 2 is at sector 0x14. | ||
2322 | This is why we have to convert project | ||
2323 | sector to project slot. The cast to int | ||
2324 | makes sure we don't accidentally end up | ||
2325 | with a float index that can be misinterpreted. */ | ||
2326 | projused[(int)((projsec-firstprojsec)/secsperproj)]=1; | ||
2327 | } | ||
2328 | } | ||
2329 | |||
2330 | int foundslotnum=0; | ||
2331 | for (i=1;i<=maxprojs;i++) | ||
2332 | { | ||
2333 | __uint32 projsec=getprojectsectornum(i); // 1-based | ||
2334 | |||
2335 | if (projsec==0) | ||
2336 | { | ||
2337 | foundslotnum=i; | ||
2338 | break; | ||
2339 | } | ||
2340 | } | ||
2341 | |||
2342 | // Now find an unused project sector | ||
2343 | __uint32 foundsecnum=0; | ||
2344 | for (i=0;i<maxprojs;i++) { | ||
2345 | if (projused[i]==0) { | ||
2346 | foundsecnum=(i*secsperproj)+firstprojsec; | ||
2347 | break; | ||
2348 | } | ||
2349 | } | ||
2350 | memutils::myfree("projused",projused); | ||
2351 | |||
2352 | if (foundslotnum==0) | ||
2353 | { | ||
2354 | // no unused slots. | ||
2355 | return NULL; | ||
2356 | } | ||
2357 | __uint32 projectid=foundslotnum; | ||
2358 | foundslotnum--; // use 0-based slot num | ||
2359 | |||
2360 | if (foundsecnum==0) { | ||
2361 | // no unsused project sectors found. | ||
2362 | // This is seriously fishy as there *are* | ||
2363 | // unused slots- so that should never happen. | ||
2364 | // Looks like we're dealing with a corrupt FS! | ||
2365 | this->writeprotected=true; | ||
2366 | return NULL; | ||
2367 | } | ||
2368 | // Now to assign the first unused project sector | ||
2369 | // to the first unused project slot. | ||
2370 | |||
2371 | // First, update the drive info. | ||
2372 | getsector_diskinfo(); | ||
2373 | |||
2374 | // Add the new project pointer to the disk info: | ||
2375 | Convert::setint32(sector_diskinfo,DRIVEINFO_PROJECTLIST+(foundslotnum*4),foundsecnum); | ||
2376 | Convert::setint32(sector_diskinfo,DRIVEINFO_LASTPROJ,foundsecnum); | ||
2377 | |||
2378 | Convert::setint32(sector_diskinfo,DRIVEINFO_PROJECTCOUNT, | ||
2379 | Convert::getint32(sector_diskinfo,DRIVEINFO_PROJECTCOUNT)+1); | ||
2380 | |||
2381 | bool isnew=true; | ||
2382 | hd24project* newproject=new hd24project(this,projectid,foundsecnum,projectname,isnew); | ||
2383 | savedriveinfo(); | ||
2384 | |||
2385 | return newproject; | ||
2386 | } | ||
2387 | |||
2388 | bool hd24fs::isallinput() | ||
2389 | { | ||
2390 | return this->allinput; | ||
2391 | } | ||
2392 | |||
2393 | void hd24fs::setallinput(bool p_allinput) | ||
2394 | { | ||
2395 | this->allinput=p_allinput; | ||
2396 | } | ||
2397 | |||
2398 | void hd24fs::setallinput(void) | ||
2399 | { | ||
2400 | this->setallinput(true); | ||
2401 | } | ||
2402 | |||
2403 | /* These three functions are for the 'auto input' button | ||
2404 | (having to do with automatic toggling of monitoring | ||
2405 | between 'tape' and inputs during a punch in */ | ||
2406 | bool hd24fs::isautoinput() | ||
2407 | { | ||
2408 | return this->autoinput; | ||
2409 | } | ||
2410 | |||
2411 | void hd24fs::setautoinput(bool p_autoinput) | ||
2412 | { | ||
2413 | this->autoinput=p_autoinput; | ||
2414 | } | ||
2415 | |||
2416 | void hd24fs::setautoinput(void) | ||
2417 | { | ||
2418 | this->setautoinput(true); | ||
2419 | } | ||
2420 | |||
2421 | void hd24fs::writebackupblock(__uint32 p_sector,__uint32 p_blocksize, | ||
2422 | __uint32 lastsec,bool fullcommit) | ||
2423 | { | ||
2424 | /** Used by commit. This writes a logical block | ||
2425 | of file system data to the end of the drive. */ | ||
2426 | unsigned char backbuf[1024]; | ||
2427 | |||
2428 | __uint32 i; | ||
2429 | __uint32 blocksize=p_blocksize; | ||
2430 | |||
2431 | if (fullcommit==false) | ||
2432 | { | ||
2433 | // we're doing a quick commit, so only backup | ||
2434 | // changed blocks. | ||
2435 | if (p_sector>highestFSsectorwritten) return; | ||
2436 | } | ||
2437 | |||
2438 | for (i=1;i<=blocksize;i++) { | ||
2439 | // read sector $sector+$i-1 | ||
2440 | // write to sector -($sector+1+$blocksize-$i) | ||
2441 | // (where -1= last sector) | ||
2442 | __uint32 currentsourcesector=p_sector+(i-1); | ||
2443 | |||
2444 | readsector_noheader(this, currentsourcesector, backbuf); | ||
2445 | __uint32 targetsector=(lastsec-(p_sector+1+blocksize-i))+1; | ||
2446 | // cout << "write sec " << targetsector << endl; | ||
2447 | writesector(this->devhd24,targetsector,backbuf); | ||
2448 | } | ||
2449 | } | ||
2450 | |||
2451 | bool hd24fs::commit() | ||
2452 | { | ||
2453 | // default commit is a quick commit rather than full commit. | ||
2454 | // A quick commit only commits sectors up to the last project/song | ||
2455 | // sector changed. | ||
2456 | return this->commit(false); | ||
2457 | } | ||
2458 | bool hd24fs::commit(bool fullcommit) | ||
2459 | { | ||
2460 | /** This creates a backup of the file system to the end of the drive. */ | ||
2461 | |||
2462 | |||
2463 | #if (HD24FSDEBUG==1) | ||
2464 | cout << "hd24fs::commit()" << endl; | ||
2465 | // cout << "Driveusage before commit=" << (int)(this->sectors_driveusage) << endl; | ||
2466 | #endif | ||
2467 | if (this->headersectors!=0) | ||
2468 | { | ||
2469 | // ehm. Obviously we're not going to overwrite the | ||
2470 | // end of the drive with header file information, | ||
2471 | // as that would defeat the purpose of header files | ||
2472 | // (which is to allow safe read-only operation). | ||
2473 | return true; | ||
2474 | }; | ||
2475 | __uint32 sector=0; | ||
2476 | __uint32 blocksize=1; | ||
2477 | __uint32 count=1; | ||
2478 | __uint32 lastsec=getlastsectornum(); | ||
2479 | writebackupblock(sector,blocksize,lastsec,fullcommit); // backup superblock | ||
2480 | |||
2481 | sector+=(blocksize*count); | ||
2482 | blocksize=1; | ||
2483 | count=1; | ||
2484 | |||
2485 | writebackupblock(sector,blocksize,lastsec,fullcommit); // backup drive info | ||
2486 | |||
2487 | sector+=(blocksize*count); | ||
2488 | blocksize=3; | ||
2489 | count=1; | ||
2490 | writebackupblock(sector,blocksize,lastsec,fullcommit); // Backup undo (?) usage | ||
2491 | |||
2492 | sector+=(blocksize*count); | ||
2493 | blocksize=15; | ||
2494 | count=1; | ||
2495 | writebackupblock(sector,blocksize,lastsec,fullcommit); // Backup drive usage table | ||
2496 | |||
2497 | sector+=(blocksize*count); | ||
2498 | blocksize=1; | ||
2499 | count=99; | ||
2500 | |||
2501 | __uint32 i; | ||
2502 | for (i=1;i<=count;i++) | ||
2503 | { | ||
2504 | #if (HD24FSDEBUG_COMMIT==1) | ||
2505 | cout <<"Going to write proj backup block no. " << i << endl; | ||
2506 | #endif | ||
2507 | writebackupblock(sector+(i-1),blocksize,lastsec,fullcommit); // Backup project | ||
2508 | } | ||
2509 | |||
2510 | sector+=(blocksize*count); | ||
2511 | count=99*99; | ||
2512 | for (i=1;i<=count;i++) | ||
2513 | { | ||
2514 | #if (HD24FSDEBUG_COMMIT==1) | ||
2515 | cout <<"Going to write song backup block no. " << i << endl; | ||
2516 | #endif | ||
2517 | blocksize=2; | ||
2518 | writebackupblock(sector+(7*(i-1)),blocksize,lastsec,fullcommit); // Backup song | ||
2519 | |||
2520 | blocksize=5; | ||
2521 | writebackupblock(sector+(7*(i-1))+2,blocksize,lastsec,fullcommit); // Backup song alloc info | ||
2522 | } | ||
2523 | #if (HD24FSDEBUG_COMMIT==1) | ||
2524 | cout <<"Wrote backup blocks" << endl; | ||
2525 | cout << "Driveusage after commit=" << (int)(this->sectors_driveusage) << endl; | ||
2526 | #endif | ||
2527 | highestFSsectorwritten=0; // reset | ||
2528 | return true; | ||
2529 | } | ||
2530 | |||
2531 | long unsigned int hd24fs::setsectorchecksum(unsigned char* buffer,unsigned int startoffset,unsigned int startsector,unsigned int sectors) | ||
2532 | { | ||
2533 | // Calculates and sets the checksum for a block of data. | ||
2534 | // Data must be in drive-native format. | ||
2535 | long unsigned int checksum32 = 0; | ||
2536 | unsigned long int totbytes=(SECTORSIZE*sectors); | ||
2537 | |||
2538 | buffer[startoffset+totbytes-8]=startsector%256; | ||
2539 | buffer[startoffset+totbytes-7]=(startsector>>8)%256; | ||
2540 | buffer[startoffset+totbytes-6]=255- buffer[startoffset+totbytes-8]; | ||
2541 | buffer[startoffset+totbytes-5]=255- buffer[startoffset+totbytes-7]; | ||
2542 | |||
2543 | for (unsigned long i = 0; i < totbytes; i += 4) | ||
2544 | { | ||
2545 | unsigned long num = Convert::getint32(buffer, i+startoffset); | ||
2546 | int byte1 = num % 256; | ||
2547 | int byte2 = (num >> 8) % 256; | ||
2548 | int byte3 = (num >> 16) % 256; | ||
2549 | int byte4 = (num >> 24) % 256; | ||
2550 | num = byte4 + (byte3 << 8) + (byte2 << 16) + (byte1 << 24); | ||
2551 | checksum32 += num; | ||
2552 | } | ||
2553 | unsigned long oldchecksum=0; | ||
2554 | oldchecksum+=((unsigned char)(buffer[startoffset+totbytes-1])); oldchecksum=oldchecksum <<8; | ||
2555 | oldchecksum+=((unsigned char)(buffer[startoffset+totbytes-2])); oldchecksum=oldchecksum <<8; | ||
2556 | oldchecksum+=((unsigned char)(buffer[startoffset+totbytes-3])); oldchecksum=oldchecksum <<8; | ||
2557 | oldchecksum+=((unsigned char)(buffer[startoffset+totbytes-4])); | ||
2558 | oldchecksum-=checksum32; | ||
2559 | buffer[startoffset+totbytes-4]=oldchecksum%256; oldchecksum=oldchecksum >> 8; | ||
2560 | buffer[startoffset+totbytes-3]=oldchecksum%256; oldchecksum=oldchecksum >> 8; | ||
2561 | buffer[startoffset+totbytes-2]=oldchecksum%256; oldchecksum=oldchecksum >> 8; | ||
2562 | buffer[startoffset+totbytes-1]=oldchecksum%256; oldchecksum=oldchecksum >> 8; | ||
2563 | return checksum32; | ||
2564 | } | ||
2565 | |||
2566 | void hd24fs::savedriveinfo() | ||
2567 | { | ||
2568 | // This is capable of handling only 1-sector-per-project projects | ||
2569 | __uint32 driveinfosector=1; | ||
2570 | if (sector_diskinfo==NULL) | ||
2571 | { | ||
2572 | // diskinfo is not available, nothing to do. | ||
2573 | return; | ||
2574 | } | ||
2575 | #if (HD24FSDEBUG==1) | ||
2576 | cout << "FSTFIX" << endl; | ||
2577 | #endif | ||
2578 | this->fstfix(sector_diskinfo,512); // sector is now once again in native format | ||
2579 | |||
2580 | #if (HD24FSDEBUG==1) | ||
2581 | cout << "set checksum" << endl; | ||
2582 | #endif | ||
2583 | this->setsectorchecksum(sector_diskinfo,0,driveinfosector,1); | ||
2584 | #if (HD24FSDEBUG==1) | ||
2585 | cout << "write sectors" << endl; | ||
2586 | #endif | ||
2587 | this->writesectors(this->devhd24, | ||
2588 | driveinfosector, | ||
2589 | sector_diskinfo,1); | ||
2590 | |||
2591 | #if (HD24FSDEBUG==1) | ||
2592 | cout << "unfix" << endl; | ||
2593 | #endif | ||
2594 | this->fstfix(sector_diskinfo,512); // sector is now in 'fixed' format | ||
2595 | #if (HD24FSDEBUG==1) | ||
2596 | cout << "commit" << endl; | ||
2597 | #endif | ||
2598 | this->commit(); | ||
2599 | } | ||
2600 | |||
2601 | void hd24fs::setname(unsigned char* namebuf,string newname,__uint32 shortnameoff,__uint32 longnameoff) | ||
2602 | { | ||
2603 | /** Used for setting song/project/drive names | ||
2604 | Long name is up to 64 characters; short name | ||
2605 | is up to 10 chars. | ||
2606 | */ | ||
2607 | #if (HD24FSDEBUG==1) | ||
2608 | cout << "hd24fs::setname(" | ||
2609 | << "*namebuf=" << *namebuf << "," | ||
2610 | << "newname=" << newname << "," | ||
2611 | << "shortnameoff="<<shortnameoff << "," | ||
2612 | << "longnameoff=" << longnameoff <<");" << endl; | ||
2613 | #endif | ||
2614 | bool foundzero=false; | ||
2615 | for (__uint32 i=0;i<64;i++) | ||
2616 | { | ||
2617 | if (!foundzero) | ||
2618 | { | ||
2619 | namebuf[longnameoff+i]=newname.c_str()[i]; | ||
2620 | if (namebuf[longnameoff+i]==0) { | ||
2621 | foundzero=true; | ||
2622 | #if (HD24FSDEBUG==1) | ||
2623 | cout << "Found zero at " << i << endl; | ||
2624 | #endif | ||
2625 | } | ||
2626 | } | ||
2627 | else | ||
2628 | { | ||
2629 | namebuf[longnameoff+i]=0; | ||
2630 | } | ||
2631 | } | ||
2632 | // Now set FST 1.0 short name | ||
2633 | unsigned char* target=namebuf+shortnameoff; | ||
2634 | foundzero=false; | ||
2635 | __uint32 count=0; | ||
2636 | for (__uint32 i=0;i<10;i++) | ||
2637 | { | ||
2638 | if (!foundzero) | ||
2639 | { | ||
2640 | target[count]=newname.c_str()[i]; | ||
2641 | if (target[count]==0) | ||
2642 | { | ||
2643 | foundzero=true; | ||
2644 | } | ||
2645 | } | ||
2646 | else | ||
2647 | { | ||
2648 | target[count]=0x20; /* short name is filled out | ||
2649 | with spaces */ | ||
2650 | |||
2651 | } | ||
2652 | count++; | ||
2653 | if (count==8) | ||
2654 | { | ||
2655 | count=0; | ||
2656 | target+=10; | ||
2657 | } | ||
2658 | } | ||
2659 | return; | ||
2660 | } | ||
2661 | |||
2662 | void hd24fs::savedriveusage() | ||
2663 | { | ||
2664 | __uint32 driveusagesector=5; | ||
2665 | __uint32 totsectors=15; | ||
2666 | this->fstfix(sectors_driveusage,totsectors*512); // sector is now once again in native format | ||
2667 | |||
2668 | this->setsectorchecksum(sectors_driveusage,0,driveusagesector,totsectors); | ||
2669 | this->writesectors(this->devhd24, | ||
2670 | driveusagesector, | ||
2671 | sectors_driveusage,totsectors); | ||
2672 | |||
2673 | this->fstfix(sectors_driveusage,totsectors*512); // sector is now in 'fixed' format | ||
2674 | #if (HD24FSDEBUG==1) | ||
2675 | cout << "free cluster count=" << freeclustercount() << endl; | ||
2676 | #endif | ||
2677 | unsigned char* bootrec=readbootinfo(); | ||
2678 | // update FSINFO_FREE_CLUSTERS_ON_DISK | ||
2679 | |||
2680 | Convert::setint32(bootrec,FSINFO_FREE_CLUSTERS_ON_DISK,freeclustercount()); | ||
2681 | fstfix(bootrec,512); // convert back into native format | ||
2682 | |||
2683 | /* Calculate the proper checksum for the bootinfo */ | ||
2684 | setsectorchecksum(bootrec, | ||
2685 | 0 /* startoffset */, | ||
2686 | 0 /* sector */, | ||
2687 | 1 /*sectorcount */ | ||
2688 | ); | ||
2689 | this->writesectors(this->devhd24, 0,bootrec,1); | ||
2690 | fstfix(bootrec,512); // convert back into fixed format | ||
2691 | this->commit(); | ||
2692 | } | ||
2693 | |||
2694 | |||
2695 | __uint32 hd24fs::writesuperblock(__uint32 lastsec) | ||
2696 | { | ||
2697 | // writes a new superblock to an unformatted drive. | ||
2698 | // | ||
2699 | // normal start of data area=1397f6 | ||
2700 | // size of 1 audio block=0x480 sectors | ||
2701 | // fs size=0x77+7*99 | ||
2702 | // so minimum usable drive is 0x1397f6+0x480+(0x77+(7*99*99)) | ||
2703 | // =0x14a8ec sectors | ||
2704 | if (lastsec<0x14a8ec) | ||
2705 | { | ||
2706 | // drive is smaller than the minimum needed for | ||
2707 | // storing at least 1 audio block. | ||
2708 | return RESULT_FAIL; | ||
2709 | } | ||
2710 | unsigned char superblock[512]; | ||
2711 | useinternalboot(superblock,lastsec); // this automatically sets sector checksum | ||
2712 | writesectors(this->devhd24,0,&superblock[0],1); | ||
2713 | #if (HD24FSDEBUG_QUICKFORMAT==1) | ||
2714 | |||
2715 | cout << "Writing superblock." << endl; | ||
2716 | dumpsector((const char*)superblock); | ||
2717 | |||
2718 | #endif | ||
2719 | |||
2720 | force_reload(); | ||
2721 | |||
2722 | readbootinfo(); | ||
2723 | |||
2724 | #if (HD24FSDEBUG_CLUSTERddCALC==1) | ||
2725 | cout << "Displaying sector after reload." << endl; | ||
2726 | dumpsector((const char*)sector_boot); | ||
2727 | #endif | ||
2728 | |||
2729 | return RESULT_SUCCESS; | ||
2730 | } | ||
2731 | |||
2732 | void hd24fs::force_reload() | ||
2733 | { | ||
2734 | #if (HD24FSDEBUG==1) | ||
2735 | cout << "Free superblock mem" << endl; | ||
2736 | #endif | ||
2737 | if (sector_boot!=NULL) | ||
2738 | { | ||
2739 | memutils::myfree("sectors_boot",sector_boot); | ||
2740 | sector_boot=NULL; | ||
2741 | } | ||
2742 | #if (HD24FSDEBUG==1) | ||
2743 | cout << "Free diskinfo mem" << endl; | ||
2744 | #endif | ||
2745 | if (sector_diskinfo!=NULL) | ||
2746 | { | ||
2747 | memutils::myfree("sectors_diskinfo",sector_diskinfo); | ||
2748 | sector_diskinfo=NULL; | ||
2749 | } | ||
2750 | #if (HD24FSDEBUG==1) | ||
2751 | cout << "Free drive usage mem" << endl; | ||
2752 | #endif | ||
2753 | if (sectors_driveusage!=NULL) | ||
2754 | { | ||
2755 | memutils::myfree("sectors_driveusage",sectors_driveusage); | ||
2756 | sectors_driveusage=NULL; | ||
2757 | } | ||
2758 | #if (HD24FSDEBUG==1) | ||
2759 | cout << "Free orphan sectors mem" << endl; | ||
2760 | #endif | ||
2761 | if (sectors_orphan!=NULL) | ||
2762 | { | ||
2763 | memutils::myfree("sectors_orphan",sectors_orphan); | ||
2764 | sectors_orphan=NULL; | ||
2765 | } | ||
2766 | #if (HD24FSDEBUG==1) | ||
2767 | cout << "Free song usage sectors mem" << endl; | ||
2768 | #endif | ||
2769 | if (sectors_songusage!=NULL) | ||
2770 | { | ||
2771 | memutils::myfree("sectors_songusage",sectors_songusage); | ||
2772 | sectors_songusage=NULL; | ||
2773 | }; | ||
2774 | |||
2775 | } | ||
2776 | __uint32 hd24fs::writedriveinfo() | ||
2777 | { | ||
2778 | readdiskinfo(); | ||
2779 | cleardriveinfo(sector_diskinfo); | ||
2780 | fstfix(sector_diskinfo,512); // back into native format | ||
2781 | writesectors(this->devhd24,1,sector_diskinfo,1); | ||
2782 | if (sector_diskinfo!=NULL) { | ||
2783 | memutils::myfree("sector_diskinfo",sector_diskinfo); | ||
2784 | sector_diskinfo=NULL; // force re-read | ||
2785 | } | ||
2786 | hd24project* firstproject=createproject("Proj Name"); | ||
2787 | memutils::myfree("firstproject",firstproject); | ||
2788 | |||
2789 | if (sector_diskinfo!=NULL) { | ||
2790 | memutils::myfree("sector_diskinfo",sector_diskinfo); | ||
2791 | sector_diskinfo=NULL; // force re-read | ||
2792 | } | ||
2793 | __uint32 psec=getprojectsectornum(1); | ||
2794 | if (sector_diskinfo!=NULL) { | ||
2795 | memutils::myfree("sector_diskinfo",sector_diskinfo); | ||
2796 | sector_diskinfo=NULL; // force re-read | ||
2797 | } | ||
2798 | readdiskinfo(); | ||
2799 | Convert::setint32(sector_diskinfo,DRIVEINFO_LASTPROJ,psec); | ||
2800 | savedriveinfo(); | ||
2801 | |||
2802 | return RESULT_SUCCESS; | ||
2803 | } | ||
2804 | |||
2805 | __uint32 hd24fs::writesongusage() | ||
2806 | { | ||
2807 | unsigned char* buffer=resetsongusage(); | ||
2808 | if (buffer==NULL) | ||
2809 | { | ||
2810 | return RESULT_FAIL; | ||
2811 | } | ||
2812 | __uint32 sectornum=2; | ||
2813 | __uint32 sectorcount=3; | ||
2814 | fstfix(buffer,sectorcount*512); | ||
2815 | setsectorchecksum(buffer, | ||
2816 | 0 /* startoffset */, | ||
2817 | sectornum /* sector */, | ||
2818 | sectorcount /*sectorcount */ | ||
2819 | ); | ||
2820 | this->writesectors(this->devhd24, | ||
2821 | sectornum, | ||
2822 | buffer, | ||
2823 | sectorcount); | ||
2824 | fstfix(buffer,sectorcount*512); | ||
2825 | return RESULT_SUCCESS; | ||
2826 | } | ||
2827 | |||
2828 | __uint32 hd24fs::writedriveusage() | ||
2829 | { | ||
2830 | if (sectors_driveusage!=NULL) | ||
2831 | { | ||
2832 | memutils::myfree("sectors_driveusage",sectors_driveusage); | ||
2833 | sectors_driveusage=NULL; | ||
2834 | } | ||
2835 | |||
2836 | unsigned char* buffer=resetdriveusage(); | ||
2837 | if (buffer==NULL) | ||
2838 | { | ||
2839 | return RESULT_FAIL; | ||
2840 | } | ||
2841 | __uint32 sectornum=5; | ||
2842 | __uint32 sectorcount=15; | ||
2843 | fstfix(buffer,sectorcount*512); | ||
2844 | setsectorchecksum(buffer, | ||
2845 | 0 /* startoffset */, | ||
2846 | sectornum /* sector */, | ||
2847 | sectorcount /*sectorcount */ | ||
2848 | ); | ||
2849 | |||
2850 | this->writesectors(this->devhd24, | ||
2851 | sectornum, | ||
2852 | buffer, | ||
2853 | sectorcount); | ||
2854 | fstfix(buffer,sectorcount*512); | ||
2855 | |||
2856 | return RESULT_SUCCESS; | ||
2857 | } | ||
2858 | |||
2859 | __uint32 hd24fs::quickformat(char* message) | ||
2860 | { | ||
2861 | // This procedure performs a quickformat on the current drive. | ||
2862 | // There is no need for the drive to be a valid HD24 drive | ||
2863 | // for this to work. | ||
2864 | // Safety confirmations etc. are considered to be the | ||
2865 | // responsibility of the caller. | ||
2866 | |||
2867 | gotlastsectornum=false; // force re-finding last sector num | ||
2868 | __uint32 lastsec=getlastsectornum(); | ||
2869 | |||
2870 | formatting=true; | ||
2871 | |||
2872 | if (lastsec==0) | ||
2873 | { | ||
2874 | if (message!=NULL) strcpy(message,(const char*)&"Lastsec=0"); | ||
2875 | return 0; | ||
2876 | } | ||
2877 | __uint32 result=writesuperblock(lastsec); | ||
2878 | |||
2879 | if (result==RESULT_FAIL) | ||
2880 | { | ||
2881 | if (message!=NULL) strcpy(message,(const char*)&"Write superblock failed"); | ||
2882 | return 0; // lastsec 0 means failed format | ||
2883 | } | ||
2884 | |||
2885 | result=writedriveinfo(); | ||
2886 | if (result==RESULT_FAIL) | ||
2887 | { | ||
2888 | if (message!=NULL) strcpy(message,(const char*)&"Write driveinfo failed"); | ||
2889 | return 0; // lastsec 0 means failed format | ||
2890 | } | ||
2891 | |||
2892 | result=writesongusage(); | ||
2893 | if (result==RESULT_FAIL) | ||
2894 | { | ||
2895 | if (message!=NULL) strcpy(message,(const char*)&"Write song usage failed"); | ||
2896 | return 0; // lastsec 0 means failed format | ||
2897 | } | ||
2898 | |||
2899 | result=writedriveusage(); | ||
2900 | if (result==RESULT_FAIL) | ||
2901 | { | ||
2902 | if (message!=NULL) strcpy(message,(const char*)&"Write drive usage failed"); | ||
2903 | return 0; // lastsec 0 means failed format | ||
2904 | } | ||
2905 | |||
2906 | // write empty song-entry usage table | ||
2907 | // write empty drive usage table | ||
2908 | // write 99 empty projects | ||
2909 | // create default project | ||
2910 | // (write 99*99 empty songs) | ||
2911 | // (empty audio space) | ||
2912 | // commit fs | ||
2913 | commit(); | ||
2914 | formatting=false; | ||
2915 | force_reload(); | ||
2916 | return lastsec; | ||
2917 | } | ||
2918 | |||
2919 | void hd24fs::setprojectsectornum(int i,__uint32 sector) | ||
2920 | { | ||
2921 | getsector_diskinfo(); | ||
2922 | Convert::setint32(sector_diskinfo, | ||
2923 | DRIVEINFO_PROJECTLIST + ((i - 1) * 4),sector); | ||
2924 | |||
2925 | return; | ||
2926 | } | ||
2927 | |||
2928 | __uint32 hd24fs::deleteproject(__sint32 projid) | ||
2929 | { | ||
2930 | if (projid<1) | ||
2931 | { | ||
2932 | /* Illegal project id; | ||
2933 | project IDs are set in base 1. */ | ||
2934 | return RESULT_FAIL; | ||
2935 | } | ||
2936 | |||
2937 | getsector_diskinfo(); // has list of pointers to project sectors | ||
2938 | __uint32 pcount = Convert::getint32(sector_diskinfo, DRIVEINFO_PROJECTCOUNT); | ||
2939 | |||
2940 | if (pcount<=1) | ||
2941 | { | ||
2942 | /* Attempt to delete last project on drive- | ||
2943 | not allowed, a drive must always contain | ||
2944 | at least 1 project */ | ||
2945 | return RESULT_FAIL; | ||
2946 | } | ||
2947 | |||
2948 | hd24project* projtodel=this->getproject(projid); | ||
2949 | if (projtodel==NULL) { | ||
2950 | return RESULT_FAIL; | ||
2951 | } | ||
2952 | |||
2953 | /* If there still all songs in the project, delete them */ | ||
2954 | __uint32 currsongcount=projtodel->songcount(); | ||
2955 | if (currsongcount>0) | ||
2956 | { | ||
2957 | for (__uint32 j=1; j<=currsongcount;j++) | ||
2958 | { | ||
2959 | projtodel->deletesong(1); // songs will shift | ||
2960 | projtodel->save(); | ||
2961 | } | ||
2962 | } | ||
2963 | |||
2964 | /* delete project from project list by shifting left | ||
2965 | all other projects... */ | ||
2966 | if (projid<99) | ||
2967 | { | ||
2968 | /* When project 99 is deleted no shifting is needed */ | ||
2969 | for (__uint32 i=projid;i<99;i++) | ||
2970 | { | ||
2971 | setprojectsectornum(i,getprojectsectornum(i+1)); | ||
2972 | } | ||
2973 | } | ||
2974 | |||
2975 | setprojectsectornum(99,0); // ...and clearing the last entry. | ||
2976 | |||
2977 | Convert::setint32(sector_diskinfo,DRIVEINFO_PROJECTCOUNT,pcount-1); | ||
2978 | |||
2979 | /* Set 'last accessed project' to first in list | ||
2980 | (the project being deleted needs to be accessed | ||
2981 | prior to deletion so this must always be updated) | ||
2982 | */ | ||
2983 | Convert::setint32(sector_diskinfo, DRIVEINFO_LASTPROJECT,getprojectsectornum(1)); | ||
2984 | #if (HD24FSDEBUG==1) | ||
2985 | cout << "save project." << endl; | ||
2986 | #endif | ||
2987 | |||
2988 | savedriveinfo(); | ||
2989 | delete projtodel; | ||
2990 | return RESULT_SUCCESS; | ||
2991 | } | ||
2992 | |||
2993 | void hd24fs::write_enable() | ||
2994 | { | ||
2995 | this->writeprotected=false; | ||
2996 | } | ||
2997 | |||
2998 | void hd24fs::write_disable() | ||
2999 | { | ||
3000 | this->writeprotected=true; | ||
3001 | } | ||
3002 | |||