aboutsummaryrefslogtreecommitdiff
path: root/src/lib/hd24fs.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/hd24fs.cpp')
-rwxr-xr-xsrc/lib/hd24fs.cpp3002
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)
74const int hd24fs::MODE_RDONLY=O_RDONLY;
75const int hd24fs::MODE_RDWR=O_RDWR;
76#endif
77#ifdef WINDOWS
78#include <shellapi.h>
79const int hd24fs::MODE_RDONLY=GENERIC_READ;
80const int hd24fs::MODE_RDWR=GENERIC_READ|GENERIC_WRITE;
81#define popen _popen
82#define pclose _pclose
83#endif
84
85const int hd24fs::TRANSPORTSTATUS_STOP =0;
86const int hd24fs::TRANSPORTSTATUS_REC =1;
87const int hd24fs::TRANSPORTSTATUS_PLAY =2;
88
89void 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
144void 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,&sectors_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(&sectors_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
283unsigned 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
296void hd24fs::setwavefixmode(int mode)
297{
298 wavefixmode=mode;
299}
300
301void hd24fs::setmaintenancemode(int mode)
302{
303 maintenancemode=mode;
304}
305
306int hd24fs::getmaintenancemode()
307{
308 return maintenancemode;
309}
310
311string* hd24fs::getdevicename() {
312
313 return this->devicename;
314}
315
316void 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
325unsigned 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
513unsigned long hd24raw::getnextfreesector(__uint32 cluster)
514{
515 return fsys->getnextfreesector(cluster);
516}
517
518hd24raw::hd24raw(hd24fs* p_fsys)
519{
520 fsys=p_fsys;
521}
522
523long hd24raw::readsectors(unsigned long secnum, unsigned char* buffer,int sectors)
524{
525 return fsys->readsectors(fsys->devhd24, secnum, buffer,sectors);
526}
527
528long hd24raw::writesectors(unsigned long secnum, unsigned char* buffer,int sectors)
529{
530 return fsys->writesectors(fsys->devhd24, secnum, buffer,sectors);
531};
532
533bool 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
551bool hd24fs::isexistingdevice(string* devname)
552{
553#if defined(LINUX) || defined(DARWIN)
554#if (HD24FSDEBUG==1)
555cout << "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
568FSHANDLE 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
675unsigned 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
727void hd24fs::setimagedir(const char* newdir)
728{
729#if (HD24FSDEBUG==1)
730if (newdir==NULL)
731{
732 cout << "hd24fs::setimagedir(NULL)"<< endl;
733}
734else
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
758FSHANDLE 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
815void 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
824FSHANDLE 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
831FSHANDLE hd24fs::findhd24device()
832{
833 return findhd24device(MODE_RDONLY);
834}
835
836int hd24fs::gettransportstatus()
837{
838 return this->transportstatus;
839}
840
841void hd24fs::settransportstatus(int newstatus)
842{
843 this->transportstatus=newstatus;
844}
845
846int hd24fs::getdeviceid()
847{
848 return deviceid;
849}
850
851void 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
883hd24fs::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
896hd24fs::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
912hd24fs::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
926hd24fs::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
939hd24fs::~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
998bool hd24fs::isOpen()
999{
1000 if (this->m_isOpen)
1001 {
1002 return true;
1003 }
1004 return false;
1005}
1006
1007void 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
1016void 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
1036void 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
1068long 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
1148long 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
1192long hd24fs::readsector(FSHANDLE devhd24,unsigned long sectornum,unsigned char * bootblock)
1193{
1194 return readsectors(devhd24,sectornum,bootblock,1);
1195}
1196
1197long hd24fs::readsector_noheader(hd24fs* currhd24,unsigned long sectornum,unsigned char * bootblock)
1198{
1199 return readsector_noheader(currhd24->devhd24,sectornum,bootblock);
1200}
1201
1202long 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
1211long hd24fs::writesector(FSHANDLE devhd24,unsigned long sectornum,unsigned char * bootblock)
1212{
1213 return writesectors(devhd24,sectornum,bootblock,1);
1214}
1215
1216string* 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
1227string* hd24fs::gethd24currentdir()
1228{
1229 return new string("/");
1230}
1231
1232unsigned 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
1259bool 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
1292void 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
1301void hd24fs::clearbuffer(unsigned char* buffer)
1302{
1303 clearbuffer(buffer,512);
1304}
1305
1306
1307void 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
1315void 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
1402unsigned 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
1443unsigned 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 << &sectors_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
1475unsigned 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
1517unsigned 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
1579unsigned 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
1631void 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
1671unsigned 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
1682unsigned 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
1695unsigned 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
1709unsigned 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
1727string* 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
1737void 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
1747unsigned 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
1763unsigned 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
1787void 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
1805void 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
1832unsigned 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
1843unsigned 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
1877bool 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
1897void 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
1916void 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
1938bool hd24fs::isfreecluster(unsigned long i,unsigned char* usagebuffer)
1939{
1940 return isbitzero(i,usagebuffer);
1941}
1942
1943void hd24fs::allocatecluster(__uint32 clusternum,unsigned char* usagebuffer)
1944{
1945 enablebit(clusternum,usagebuffer);
1946}
1947
1948void hd24fs::freecluster(__uint32 clusternum,unsigned char* usagebuffer)
1949{
1950 disablebit(clusternum,usagebuffer);
1951}
1952void hd24fs::allocatecluster(__uint32 clusternum)
1953{
1954 allocatecluster(clusternum,sectors_driveusage);
1955}
1956
1957void hd24fs::freecluster(__uint32 clusternum)
1958{
1959 freecluster(clusternum,sectors_driveusage);
1960}
1961
1962unsigned 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
2007string* 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
2048string* 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
2063unsigned 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
2081unsigned 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
2099unsigned long hd24fs::getbytesperaudioblock()
2100{
2101 return getblocksizeinsectors()*512;
2102}
2103
2104unsigned 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
2115unsigned 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
2154void 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
2176signed 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
2239void hd24fs::allocsongentry(unsigned long songentry)
2240{
2241 enablebit(songentry,sectors_songusage);
2242}
2243
2244unsigned 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
2262int hd24fs::mode() {
2263 return p_mode;
2264}
2265
2266hd24project* 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
2275hd24project* 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
2388bool hd24fs::isallinput()
2389{
2390 return this->allinput;
2391}
2392
2393void hd24fs::setallinput(bool p_allinput)
2394{
2395 this->allinput=p_allinput;
2396}
2397
2398void 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 */
2406bool hd24fs::isautoinput()
2407{
2408 return this->autoinput;
2409}
2410
2411void hd24fs::setautoinput(bool p_autoinput)
2412{
2413 this->autoinput=p_autoinput;
2414}
2415
2416void hd24fs::setautoinput(void)
2417{
2418 this->setautoinput(true);
2419}
2420
2421void 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
2451bool 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}
2458bool 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
2531long 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
2566void 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
2601void 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
2662void 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
2732void 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
2919void 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
2993void hd24fs::write_enable()
2994{
2995 this->writeprotected=false;
2996}
2997
2998void hd24fs::write_disable()
2999{
3000 this->writeprotected=true;
3001}
3002