-
Notifications
You must be signed in to change notification settings - Fork 4
Expand file tree
/
Copy pathdevice.cpp
More file actions
4090 lines (3381 loc) · 114 KB
/
device.cpp
File metadata and controls
4090 lines (3381 loc) · 114 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/*
19980620 mvh Setting MAGDeviceThreshHold to 0 causes out of disk error below 10 MB without cleanup
19980620 mvh Implemented PanicKillOff thread here as alternative to spawning killer.exe
19980702 mvh Started support functions for maintaining/determining amount of used space on device
19980704 mvh NOTE: JukeBox code only TruncateFieldNames compatible for now; used mp's filecopy
19980709 mvh Finished first version of archive options: prepare,undo,copy,compare,delete
19980721 mvh Set default # cache and jukebox devices to 0
19990110 mvh Made strings longer since got truncated, fixed some messages
19990110 mvh Archive one MAG device or MAG?; fixed SQL syntax for update; speeded 0x7fffffff
return False if SelectLRUForarchival selects no data
19990111 mvh Reset archive flag reports to operator console; protected against illegal device#
19990113 mvh Run up to 10 patient further to try and fill CD more exact; max patients = 10000
19990114 mvh Added quick routine MakeListOfPatientsOnDevice and used instead of 0x7fffffff
19990117 mvh Accept any, not only *.v2, for computing patient size, assume max file size=30 MB
19990630 mvh Added support for MIRROR devices (e.g., try MIRROR1 if MAG1 fails)
19990707 mvh Fixed default MIRRORDevices (now 0)
19990708 mvh NOTE: archiving should make use of mirror device if required as well!
19990712 mvh Fixed that MagRampage thread was started over and over again (fixed for WIN32 only)
19990831 ljz Fix: Several BOOL functions returned -1, which is TRUE !!
20000221 ljz Changed layout of this update-history
20000629 ljz Logging of trouble now starts with '***'
20001104 mvh Fixed aDB.Close -> should be aDB.Close(); added WINAPI to MagRampage thread
20010328 mvh Added verify mirror disk
20010329 mvh DeleteBunchAfterBurning also deletes data on MIRROR0 if it exists
verify mirror disk keeps on going after error but does return error
20010312 mvh Check if we already selected some patients for archiving from the device
20010509 mvh Added RenameDevice
20010522 mvh+ljz Do not call RestoreMagFlags if something goes in wrong in PrepareBunchForBurning
20011114 ljz+mvh Replaced slow updates for magdevice by much faster ones
The update that now no longer has the IN part might not work for ACCESS or DBF
So: for jukebox purposes, SQL server is required
20011115 ljz+mvh Replaced 'LIKE' by faster '=' in query strings; fixed previous fix
20020412 mvh PanicKilloff will delete now delete 5 MB data at a time. (high water = low water + 5)
20020415 mvh Added TestImages: sanity check of images on disk
20020416 mvh Reversed read order for TestImages and VerifyMirrorDisk: MRU first
20020802 mvh Allow multiple subdirectories in rmdir and mkdir code
20020804 mvh Cleaned up a bit
20021018 mvh GenerateFileName has NoKill option (for interactive dgate tasks); moved ALERT warning
20021020 mvh Simplified and speeded queries for archiving using ImagePat field (requires rev5+ of db)
Removed " and added [ in MakeSafeString; hand-code one query for built-in dbase driver
Changed SQL construct in SelectLRUForArchival for compatibility with built-in driver
20030120 ljz Added FreeDeviceTables
20030702 mvh Start on ArchiveCompression; for now KB is specified -before!- compression
20030705 mvh Replaced ProcessDDO by more correct DecompressNKI to check pixel data
20030706 mvh Attach VRType to PDU's for implicit little endian support
20030724 ljz Fix in GetKBUsedForPatient: missing %s in printf
20030819 mvh Allow longer filenames
20030905 mvh Allow longer filenames when reading device paths
20030921 mvh Added DEVICE_TYPE_MIRROR in GetDevice; allow PanicKillOff to be called with variable treshold
20031217 ljz Fix: Support harddisks bigger than 2 GigaByte!!! in CalcMegsOnDevice (Thanks to Clifford Sweet)
20040403 mvh Moved ArchiveCompression to SelectLRUForArchival -> fills disks correctly
20040614 mvh Added MoveDataToDevice
20050107 mvh Adapted for linux compile (no threads yet, no check of disk space on device)
20050109 mvh Added threads for linux
20050118 mvh Detach thread after starting it to avoid leaks
20050119 mvh GetKBUsedOnDevice is not used --> no problem to return -1 under linux
20050119 mvh GetKBUsedOnDevice is not used --> no problem to return -1 under linux
20050414 mvh Fix CalcMegsOnDevice for relative path
20050421 mvh Fix: MAGThreshHold is space for largest file != space for cleanup
Now set to 30 MB independent of MAGDeviceThreshHold
20050901 mvh Fix free space check for unc paths (error counting \)
20060311 mvh When GetDiskFreeSpaceEx fails allow storing data anyway (fix for Marius Petruc)
20061213 mvh Fixed nasty bug in MakeListOfPatientsOnDevice: Query without bindfield overwrites previous bound strings!
20070316 mvh Cleanup now starts at MAGDeviceThreshHold to MAGDeviceThreshHold+1000, was start on 30 to MAGDeviceThreshHold
Allow both MAG0 and MAG0.Archiving as input for PrepareBunchForBurning
20071027 mvh Protect MakeListOfPatientsOnDevice on MAXPATIENTS; LRU selection now configurable using routine
MakeListOfOldestPatientsOnDevice. E.g. if LRUSort = StudyDate, deletes or archives least recent
scanned patients first. The default "" means that the original sort order on db entry date is kept
20071031 mvh Catch out of memory errors and return error status if so
20071118 mvh Adapted for 64 bits (use SQLLEN for BindField)
20071128 mvh Fix by kamil.krasnik of Cache device disk space test for UNIX
mvh Also fix Cache and Mirror for UNC paths
20080126 mvh Fixed bug reported by Ali: second move to MAG1 of more data if same patient would fail on delete
Added new logic: attempt to delete file from MAG0 that is not in MAG0 but is in MAG1 is OK
Similar attempt to delete file from MAG0 that is in MAG0 but not in MAG1 is an error
20080302 mvh Fixed case of DICOM table names
20080317 mvh Fixed deletebunchafterburning change (Ali)
20080604 mvh Modified device searching order when file not found: JUKEBOX now also searches other JUKEBOX
20080617 mvh Fixed bug in above: second jukebox not accessed correctly
20080818 mvh DbaseIII check now uses DB flags, not PATHSEP in datasource name
20081016 mvh Fix check of max patients in MakeListofOldestPatientsOnDevice
20081120 mvh Added UseEscapeStringConstants and DoubleBackSlashToDB
20081124 mvh restrict PanicKillOff to 10 runs (to stop when no patients left)
20090821 mvh Added new FileExists function that uses stat; maybe does not try to mount tape or disk to early
20090926 mvh MakeListOfOldestPatientsOnDevice returns newest if Max<0
SelectLRUForArchival always use new code (use KB<0 to select MRU);
Default MakeListOfOldestPatientsOnDevice use AccessTime to emulate old code
20091231 bcb Changed char* to const char* for gcc4.2 warnings
20100111 mvh Merged
20100120 mvh Fixed two const issues detected with ms8
20100124 mvh Use MyGetPrivateProfileString
20100309 bcb Added double parentheses (gcc4.2 Warnings)
20100309 bcb Changed int to unsigned int, commented out unused variables and routines (gcc4.2 Warnings)
20100619 bcb Added UNUSED_ARGUMENT.
20100717 mvh Merged
20100901 mvh Added IgnoreMAGDeviceThreshHold
20101121 mvh Added ArchiveConverter0 (1900)
20110105 mvh Do not stop deleting on single error; added MoveDeviceConverter0 (2000)
20110105 mvh SelectSeriesForArchival: selects data older than age days (age>0) or younger (age<0) from device
20110106 mvh added kb limit to SelectSeriesForArchival; Added moveseriestodevice
20110106 mvh fixes in series code and new MakeSafeString; #if code to allow select on AccessTime instead of SeriesDate
20110119 mvh Pass PDU to some archiving code as script context
20110320 mvh Added MAGDeviceFullThreshHold, system will only write to device if more than # MB avail (def 30)
20110603 mvh Fully init vr used for MakeSafeString
20110606 mvh RecompressPatient also changes filename if script (ArchiveConverter0, MoveDeviceConverter0) passed
20110904 mvh Fixed leak in InitializeDeviceTable (occurs in read_ini command)
20120703 bcb Changes WIN32 & WINDOWS to !UNIX, removed WHEDGE, created and included device.hpp, fixed overflows
Moved includes, defines and prototypes to device.hpp.
Fix always false ifs; made lLRUSort (local LRUSort).
20120710 bcb Added mkdir define. Cleaned up prototypes and includes
20120722 mvh Blocked out unreachable code
20120723 mvh Fixed string overflow found by bcb in MakeListOfLRUPatients
20130226 bcb Replaced gpps with IniValue class. Removed all globals and routines now in IniValue class.
Version to 1.4.18a.
201300313 bcb Merged with 1.4.17a.
*/
# include "device.hpp"
# include "dgate.hpp"
# include "configpacs.hpp"
# include "util.h"
#ifndef UNIX
# include <direct.h>
# include <io.h>
#define PATHSEPSTR "\\"
#define PATHSEPCHAR '\\'
#else // UNIX
#define PATHSEPSTR "/"
#define PATHSEPCHAR '/'
#define stricmp(s1, s2) strcasecmp(s1, s2)
#define memicmp(s1, s2, n) strncasecmp(s1, s2, n)
#define strnicmp(s1, s2, n) strncasecmp(s1, s2, n)
#define memicmp(s1, s2, n) strncasecmp(s1, s2, n)
#define O_BINARY 0
#include <pthread.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/statvfs.h>
#endif
#include <stdio.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <time.h>
#ifdef UNIX
#define mkdir(a) mkdir(a, 0777)
#endif
BOOL
PanicKillOff(unsigned int MAGThreshHold)
{
// Query the patient table, and sort it by access time
SQLLEN sdword,sdword1;
DWORD iTime;
Database DB;
// char s[255];
char PID[256];
int i;
if(MAGThreshHold==0) MAGThreshHold = 10;
// new code that deletes patients with oldest most recent study first
IniValue *iniValuePtr = IniValue::GetInstance();
if (iniValuePtr->sscscpPtr->LRUSort[0])
{
char *PatientIDList;
int Patients;
int MAXPATIENTS = 1000;
Patients = MakeListOfOldestPatientsOnDevice(&PatientIDList, MAXPATIENTS,
"MAG0", iniValuePtr->sscscpPtr->LRUSort);
for (i=0; i<Patients; i++)
{
strncpy(PID, PatientIDList + 256*i, 255);
PID[255]=0;
VR *vr = new VR(0x0010, 0x0020, strlen(PID), (void*)PID, (BOOL) FALSE );
DICOMDataObject DDO;
OperatorConsole.printf("DISK SPACE: %d MB / NEED %d MB - Deleting patient on %s: %s\n",
LargestFreeMAG(), MAGThreshHold, iniValuePtr->sscscpPtr->LRUSort, PID);
DDO.Push(vr);
RemoveFromPACS(&DDO);
if(LargestFreeMAG()>MAGThreshHold + 5) // make 5 MB extra room
break;
else
continue;
}
free(PatientIDList);
return TRUE;
}
// original code that deletes patient on db order
for (i=0; i<10; i++)
{
if (!DB.Open ( iniValuePtr->sscscpPtr->DataSource, iniValuePtr->sscscpPtr->UserName,
iniValuePtr->sscscpPtr->Password, iniValuePtr->sscscpPtr->DataHost ) )
return ( FALSE );
if (!DB.Query(iniValuePtr->sscscpPtr->PatientTableName, "AccessTime, PatientID", NULL, "AccessTime"))
return (FALSE);
if(!DB.BindField (1, SQL_C_ULONG,
&iTime, 4,
&sdword1))
return ( FALSE );
if(!DB.BindField (2, SQL_C_CHAR,
PID, 255,
&sdword))
return ( FALSE );
while(DB.NextRecord())
{
VR *vr = new VR(0x0010, 0x0020, strlen(PID), (void*)PID, (BOOL) FALSE );
DICOMDataObject DDO;
OperatorConsole.printf("DISK SPACE: %d MB / NEED %d MB - Deleting patient: %s\n", LargestFreeMAG(), MAGThreshHold, PID);
DDO.Push(vr);
RemoveFromPACS(&DDO);
if(LargestFreeMAG()>MAGThreshHold + 5) // make 5 MB extra room
{
DB.Close();
return ( TRUE );
}
else
continue;
}
}
DB.Close();
OperatorConsole.printf("DISK SPACE: %d MB / NEED %d MB - but stopping\n", LargestFreeMAG(), MAGThreshHold);
return ( TRUE );
}
////////////////////////////////////////////////////////////////////////
// start a killer to make some space by deleting LRU patients
#ifndef UNIX
static HANDLE ThreadHandle=NULL;
#endif
BOOL
#ifndef UNIX
WINAPI
#endif
MAGRampage()
{
PanicKillOff(IniValue::GetInstance()->sscscpPtr->MAGDeviceThreshHold+1000);
#ifndef UNIX
CloseHandle(ThreadHandle);
ThreadHandle = NULL;
#endif
return ( TRUE );
}
////////////////////////////////////////////////////////////////////////
// find amount of space on disk with most space
UINT
LargestFreeMAG()
{
unsigned int Index, aSize;
UINT Max = 0, iMax;
Index = 0;
IniValue *iniValuePtr = IniValue::GetInstance();
if(iniValuePtr->sscscpPtr->MAGDevicePtr != NULL)
{
aSize = iniValuePtr->sscscpPtr->MAGDevicePtr->GetSize();
while ( Index < aSize)
{
iMax = CheckFreeStoreOnMAGDevice(Index);
if(iMax>Max) Max = iMax;
++Index;
}
}
return ( Max );
}
////////////////////////////////////////////////////////////////////////
// find magnetic device with largest amount of space
UINT
MaxMagDevice ()
{
unsigned int Index, aSize;
UINT Max = 0, iMax, Device = 0;
Index = 0;
IniValue *iniValuePtr = IniValue::GetInstance();
if(iniValuePtr->sscscpPtr->MAGDevicePtr != NULL)
{
aSize = iniValuePtr->sscscpPtr->MAGDevicePtr->GetSize();
while ( Index < aSize)
{
iMax = CheckFreeStoreOnMAGDevice(Index);
if(iMax>Max)
{
Max = iMax;
Device = Index;
}
++Index;
}
}
return ( Device );
}
////////////////////////////////////////////////////////////////////////
// find cache device with largest amount of space
int
MaxCACHEDevice
(UINT NeededSpace)
{
unsigned int Max = 0, iMax, Index, aSize;
int Device = -1;
Index = 0;
IniValue *iniValuePtr = IniValue::GetInstance();
if(iniValuePtr->sscscpPtr->CACHEDevicePtr == NULL ) return -1;
aSize = iniValuePtr->sscscpPtr->CACHEDevicePtr->GetSize();
while ( Index < aSize)
{
iMax = CheckFreeStoreOnCACHEDevice(Index);
if(iMax>Max)
{
Max = iMax;
Device = Index;
}
++Index;
}
if (Max < NeededSpace)
return -1;
else
return Device;
}
////////////////////////////////////////////////////////////////////////
// find amount of free space on a disk
#ifndef UNIX
UINT
CalcMegsOnDevice(
char *RootDirectory)
/*
{
DWORD SectorsPerCluster;
DWORD BytesPerSector;
DWORD FreeClusters;
DWORD TotalClusters;
DWORD SP;
if(GetDiskFreeSpace(RootDirectory,
&SectorsPerCluster,
&BytesPerSector,
&FreeClusters,
&TotalClusters))
{
SP = (SectorsPerCluster * FreeClusters) / 1024;
SP = (SP * BytesPerSector) / 1024;
SystemDebug.printf("FreeStore Left %d on %s (%d,%d,%d,%d)\n", SP, RootDirectory,
SectorsPerCluster, BytesPerSector, FreeClusters, TotalClusters);
return ( SP );
}
SystemDebug.printf("***Error getting free store for device %s\n", RootDirectory);
return(0);
}
*/
/* Following code works correctly for harddisks with capacity above 2 GigaByte.
(thanks to Clifford Sweet)
*/
{
ULARGE_INTEGER FreeBytesAvailable;
ULARGE_INTEGER TotalNumberOfBytes;
ULARGE_INTEGER TotalNumberOfFreeBytes;
DWORD SP;
char *rd;
if (IniValue::GetInstance()->sscscpPtr->IgnoreMAGDeviceThreshHold) return 10000;
// UNC paths and drive: are OK, but use NULL (cur drive) to fix for relative paths
rd = RootDirectory;
if (rd[1]!=':' && (rd[0]!='\\' || rd[1]!='\\')) rd=NULL;
if(GetDiskFreeSpaceEx(rd,
&FreeBytesAvailable,
&TotalNumberOfBytes,
&TotalNumberOfFreeBytes))
{
SP = (DWORD) (FreeBytesAvailable.QuadPart >> 20);
SystemDebug.printf("FreeStore Left %d on %s\n", SP, RootDirectory);
return ( SP );
}
SystemDebug.printf("***Error getting free store for device %s\n", RootDirectory);
return(1000);
}
#else // UNIX
UINT
CalcMegsOnDevice(const char *theRootDirectory)
{
size_t aFreeSpace = 0;
struct statvfs aStat;
// statvfs() takes any path name and returns info on the device
// containing that path (file or directory)
if (IniValue::GetInstance()->sscscpPtr->IgnoreMAGDeviceThreshHold) return 10000;
if(!statvfs(theRootDirectory, &aStat))
{
aFreeSpace =
(size_t)(((double)aStat.f_bavail * (double)aStat.f_frsize) /
((double)1024 * (double)1024));
SystemDebug.printf("FreeStore Left %d on %s\n", aFreeSpace,
theRootDirectory);
}
else
{
SystemDebug.printf("***Error getting free store for device %s\n",
theRootDirectory);
}
return aFreeSpace;
}
#endif // UNIX
////////////////////////////////////////////////////////////////////////
// Find amount of space on MAG device N
#ifndef UNIX
UINT
CheckFreeStoreOnMAGDevice(
UINT MagNumber)
{
int Index;
char s[1024];
IniValue *iniValuePtr = IniValue::GetInstance();
if (iniValuePtr->sscscpPtr->MAGDevicePtr == NULL ||
MagNumber >= iniValuePtr->sscscpPtr->MAGDevicePtr->GetSize()) return 0;
strcpy(s, iniValuePtr->sscscpPtr->MAGDevicePtr->Get(MagNumber));
// Check for UNC style name
if(!strncmp(s, "\\\\", 2))
{
// UNC Name
Index = 2;
while(1)
{
if(s[Index]=='\\')
break;
++Index;
}
++Index; // mvh 20050901
while(s[Index])
{
if(s[Index]=='\\')
{
s[Index]='\0';
return(CalcMegsOnDevice(s));
}
++Index;
}
return(CalcMegsOnDevice(s));
}
s[3] = '\0';
return(CalcMegsOnDevice(s));
}
#else
// UNIX version...
UINT
CheckFreeStoreOnMAGDevice(
UINT MagNumber)
{
IniValue *iniValuePtr = IniValue::GetInstance();
if (iniValuePtr->sscscpPtr->MAGDevicePtr == NULL ||
MagNumber >= iniValuePtr->sscscpPtr->MAGDevicePtr->GetSize()) return 0;
return(CalcMegsOnDevice(iniValuePtr->sscscpPtr->MAGDevicePtr->Get(MagNumber)));
}
#endif
////////////////////////////////////////////////////////////////////////
// Find amount of space on MIRROR device N
#ifndef UNIX
UINT
CheckFreeStoreOnMIRRORDevice(
UINT MIRRORNumber)
{
int Index;
char s[1024];
IniValue *iniValuePtr = IniValue::GetInstance();
if(iniValuePtr->sscscpPtr->MIRRORDevicePtr == NULL ) return 0;
unsigned int aSize = iniValuePtr->sscscpPtr->MIRRORDevicePtr->GetSize();
if (MIRRORNumber >= aSize ) return 0;
strcpy(s, iniValuePtr->sscscpPtr->MIRRORDevicePtr->Get(MIRRORNumber));
// Check for UNC style name
if(!strncmp(s, "\\\\", 2))
{
// UNC Name
Index = 2;
while(1)
{
if(s[Index]=='\\')
break;
++Index;
}
++Index; // mvh 20071128
while(s[Index])
{
if(s[Index]=='\\')
{
s[Index]='\0';
return(CalcMegsOnDevice(s));
}
++Index;
}
return(CalcMegsOnDevice(s));
}
s[3] = '\0';
return(CalcMegsOnDevice(s));
}
#else
// UNIX version...
UINT
CheckFreeStoreOnMIRRORDevice(
UINT MIRRORNumber)
{
IniValue *iniValuePtr = IniValue::GetInstance();
if(iniValuePtr->sscscpPtr->MIRRORDevicePtr == NULL ) return 0;
unsigned int aSize = iniValuePtr->sscscpPtr->MIRRORDevicePtr->GetSize();
if (MIRRORNumber >= aSize/* || MIRRORNumber < 0*/) return 0;// bcb always false UINT < 0
return(CalcMegsOnDevice(iniValuePtr->sscscpPtr->MIRRORDevicePtr->Get(MIRRORNumber)));
}
#endif
////////////////////////////////////////////////////////////////////////
// Find amount of space on CACHE device N
#ifndef UNIX
UINT
CheckFreeStoreOnCACHEDevice(
UINT CACHENumber)
{
int Index;
char s[1024];
IniValue *iniValuePtr = IniValue::GetInstance();
if(iniValuePtr->sscscpPtr->CACHEDevicePtr == NULL ) return 0;
unsigned int aSize = iniValuePtr->sscscpPtr->CACHEDevicePtr->GetSize();
if (CACHENumber > aSize || CACHENumber < 0) return 0;
strcpy(s, iniValuePtr->sscscpPtr->CACHEDevicePtr->Get(CACHENumber));
// Check for UNC style name
if(!strncmp(s, "\\\\", 2))
{
// UNC Name
Index = 2;
while(1)
{
if(s[Index]=='\\')
break;
++Index;
}
++Index; // mvh 20071128
while(s[Index])
{
if(s[Index]=='\\')
{
s[Index]='\0';
return(CalcMegsOnDevice(s));
}
++Index;
}
return(CalcMegsOnDevice(s));
}
s[3] = '\0';
return(CalcMegsOnDevice(s));
}
#else
// UNIX version...
UINT
CheckFreeStoreOnCACHEDevice(
UINT CACHENumber)
{
char s[1024];
char* chp;
IniValue *iniValuePtr = IniValue::GetInstance();
if(iniValuePtr->sscscpPtr->CACHEDevicePtr == NULL ) return 0;
unsigned int aSize = iniValuePtr->sscscpPtr->CACHEDevicePtr->GetSize();
if (CACHENumber >= aSize/* || CACHENumber < 0*/) return 0;// bcb always false UINT < 0
strcpy(s, iniValuePtr->sscscpPtr->CACHEDevicePtr->Get(CACHENumber));
if ((chp = strchr(s, '%')))
{
chp[0] = '\0';
if ((chp = strrchr(s, '/')))
{
chp[0] = '\0';
}
}
return(CalcMegsOnDevice(s));
}
#endif
////////////////////////////////////////////////////////////////////////
// Locate a device that is suitable to store a new image on
// Note: Assumes that 30 MB is enough to store a single image
BOOL
GetDevice(
char *DeviceName,
UINT DeviceFlags)
{
UINT Index;
//UINT MAGThreshHold = 30;
#ifndef UNIX
DWORD ThreadID;
#else
pthread_t ThreadID;
#endif
// mvh 20050421: MAGThreshHold is space for largest file != space for cleanup MAGDeviceThreshHold
// if(MAGDeviceThreshHold) MAGThreshHold = MAGDeviceThreshHold;
IniValue *iniValuePtr = IniValue::GetInstance();
if(DeviceFlags&DEVICE_TYPE_MAG)
{
Index = 0;
if(iniValuePtr->sscscpPtr->MAGDevicePtr == NULL) return false;
while ( Index < iniValuePtr->sscscpPtr->MAGDevicePtr->GetSize() )
{
unsigned int c = CheckFreeStoreOnMAGDevice(Index);
if( c > iniValuePtr->sscscpPtr->MAGDeviceFullThreshHold)
{
sprintf(DeviceName, "MAG%d", Index);
if (c < iniValuePtr->sscscpPtr->MAGDeviceThreshHold && iniValuePtr->sscscpPtr->MAGDeviceThreshHold!=0)
goto cleanup;
return ( TRUE );
}
++Index;
}
if (DeviceFlags&DEVICE_TYPE_MIRROR)
{
Index = 0;
unsigned int aSize = 0;
if(iniValuePtr->sscscpPtr->MIRRORDevicePtr != NULL )
aSize = iniValuePtr->sscscpPtr->MIRRORDevicePtr->GetSize();
while ( Index < aSize )
{
if(CheckFreeStoreOnMIRRORDevice(Index) > iniValuePtr->sscscpPtr->MAGDeviceFullThreshHold)
{
sprintf(DeviceName, "MIRROR%d", Index);
return ( TRUE );
}
++Index;
}
}
// Report out of disk without attempt to cleanup if MAGDeviceThreshHold==0 or when not a server
if(!(iniValuePtr->sscscpPtr->MAGDeviceThreshHold) || (DeviceFlags & DEVICE_TYPE_NOKILL) ) return FALSE;
// god help us; no disk found with enough space
sprintf(DeviceName, "MAG%d", MaxMagDevice ());
cleanup:
#ifndef UNIX
if (!ThreadHandle)
{
OperatorConsole.printf("***ALERT: RUNNING OUT OF FREE SPACE\n");
ThreadHandle = CreateThread(NULL, 0x0000f000,
(LPTHREAD_START_ROUTINE) MAGRampage, NULL, 0, &ThreadID);
}
#else // UNIX
OperatorConsole.printf("***ALERT: RUNNING OUT OF FREE SPACE\n");
pthread_create(&ThreadID, NULL, (void*(*)(void*))MAGRampage, NULL);
pthread_detach(ThreadID);
#endif
return ( TRUE );
}
else
return ( FALSE );
}
////////////////////////////////////////////////////////////////////////
// Test if a directory exists
BOOL
DirectoryExists(
char *path)
{
char temp[1024];
struct stat statbuf;
int lc= strlen(path) - 1; /* index for last char in path */
strcpy(temp, path);
if (temp[lc] == '\\' || temp[lc] == '/')
temp[lc] = 0;
if (stat(temp, &statbuf) == -1) return FALSE; /* file or path not found */
/* only directory allowed */
if ((statbuf.st_mode & (S_IFCHR | S_IFREG)) == 0)
return TRUE;
else
return FALSE;
}
////////////////////////////////////////////////////////////////////////
// Get directory for given device (MAG, MIRROR, CACHE, or JUKEBOX)
BOOL
GetPhysicalDevice(
const char *Device,
char *Physical)
{
int Num;
Physical[0] = 0;
// Check for MAG devices
// Example: MAG0 = main data storage
IniValue *iniValuePtr = IniValue::GetInstance();
if(strnileq(Device, "mag", 3))
{
Num = atoi(&Device[3]);
if (iniValuePtr->sscscpPtr->MAGDevicePtr == NULL ||
Num >= (signed int)iniValuePtr->sscscpPtr->MAGDevicePtr->GetSize() || Num < 0) return FALSE;
strcpy(Physical, iniValuePtr->sscscpPtr->MAGDevicePtr->Get(Num));
// ensure that Physical string ends with a path separator
int aLength = (int)strlen(Physical);
if(aLength <= 0)
return(FALSE);
if(Physical[aLength - 1] != PATHSEPCHAR)
{
Physical[aLength++] = PATHSEPCHAR;
Physical[aLength] = '\0';
}
return ( TRUE );
}
if(strnicmp(Device, "MIRROR", 6)==0)
{
Num = atoi(&Device[6]);
unsigned int aSize = 0;
if(iniValuePtr->sscscpPtr->MIRRORDevicePtr != NULL )
aSize = iniValuePtr->sscscpPtr->MIRRORDevicePtr->GetSize();
if (Num >= (signed int)aSize || Num < 0) return FALSE;
strcpy(Physical, iniValuePtr->sscscpPtr->MIRRORDevicePtr->Get(Num));
// ensure that Physical string ends with a path separator
int aLength = (int)strlen(Physical);
if(aLength <= 0)
return(FALSE);
if(Physical[aLength - 1] != PATHSEPCHAR)
{
Physical[aLength++] = PATHSEPCHAR;
Physical[aLength] = '\0';
}
return ( TRUE );
}
// Check CACHE device for images that has been copied for archival
// Example: CACHE0.1.123 = On cache 0, data for jukebox 1, cd 123
if(strnicmp(Device, "CACHE", 5)==0)
{
int JUKEBOXDevice=0;
int CDNumber =0;
const char *p;
char Temp[1024];
Num = atoi(&Device[5]);
if(iniValuePtr->sscscpPtr->CACHEDevicePtr == NULL ) return FALSE;
unsigned int aSize = iniValuePtr->sscscpPtr->CACHEDevicePtr->GetSize();
if (Num >= (signed int)aSize || Num < 0) return FALSE;
strcpy(Physical, iniValuePtr->sscscpPtr->CACHEDevicePtr->Get(Num));
p = strchr(Device, '.');
if (p)
{
JUKEBOXDevice = atoi(p+1);
p = strchr(p+1, '.');
if (p) CDNumber = atoi(p+1);
}
sprintf(Temp, Physical, JUKEBOXDevice, CDNumber);
strcpy(Physical, Temp);
int aLength = (int)strlen(Physical);
if(aLength <= 0)
return(FALSE);
if(Physical[aLength - 1] != PATHSEPCHAR)
{
Physical[aLength++] = PATHSEPCHAR;
Physical[aLength] = '\0';
}
return ( TRUE );
}
// Check for data on a jukebox
// Example: JUKEBOX1.123 = jukebox 1, cd 123
if(strnicmp(Device, "JUKEBOX", 7)==0)
{
int CDNumber =0;
const char *p;
char Temp[1024];
Num = atoi(&Device[7]);
if(iniValuePtr->sscscpPtr->JUKEBOXDevicePtr == NULL ) return FALSE;
unsigned int aSize = iniValuePtr->sscscpPtr->JUKEBOXDevicePtr->GetSize();
if (Num >= (signed int)aSize || Num < 0) return FALSE;
strcpy(Physical, iniValuePtr->sscscpPtr->JUKEBOXDevicePtr->Get(Num));
p = strchr(Device, '.');
if (p) CDNumber = atoi(p+1);
sprintf(Temp, Physical, CDNumber);
strcpy(Physical, Temp);
// ensure that Physical string ends with a path separator
int aLength = (int)strlen(Physical);
if(aLength <= 0)
return(FALSE);
if(Physical[aLength - 1] != PATHSEPCHAR)
{
Physical[aLength++] = PATHSEPCHAR;
Physical[aLength] = '\0';
}
return ( TRUE );
}
return(FALSE);
}
////////////////////////////////////////////////////////////////////////
// Test if a file exists
/*static BOOL
FileExistsOld(char *Path)
{
FILE *f;
// int res;
f = fopen(Path, "rb");
if (f==NULL) return FALSE;
fclose(f);
return TRUE;
}
*/
static BOOL
FileExists(
char *path)
{
struct stat statbuf;
if (stat(path, &statbuf) == -1) return FALSE; // file or path not found
// regular file
if (statbuf.st_mode & S_IFREG)
return TRUE;
else
return FALSE;
}
////////////////////////////////////////////////////////////////////////
// Find directory that contains a given image file on all MAG, CACHE, or JUKEBOX devices
BOOL
FindPhysicalDevice(
char *Device,
char *Physical,
char *ObjectFile)
{
char FileName[1024], Temp[1024];
int number=-1, sub1=-1, sub2=-1;
unsigned int i, aSize;
char *p;
SystemDebug.printf("Locating file:%s %s\n", Device, ObjectFile);
// interpret the device name
if(strnicmp(Device, "MAG", 3)==0)
number = atoi(Device + 3);
else if(strnicmp(Device, "MIRROR", 6)==0)
number = atoi(Device + 6);
else if(strnicmp(Device, "CACHE", 5)==0)
number = atoi(Device + 5);
else if(strnicmp(Device, "JUKEBOX", 7)==0)
number = atoi(Device + 7);
// try listed device first (it may be right !)
GetPhysicalDevice(Device, Physical);
strcpy(FileName, Physical);
strcat(FileName, ObjectFile);
if (FileExists(FileName))
return TRUE;
// get device sub-numbers
p = strchr(Device, '.');
if (p)
{
sub1 = atoi(p+1);
p = strchr(p+1, '.');
if (p) sub2 = atoi(p+1);
}
IniValue *iniValuePtr = IniValue::GetInstance();
// for MAG try MIRROR device (disk may be corrupt or not updated yet from slow mirror server)
if(strnicmp(Device, "MAG", 3)==0)
{
sprintf(Temp, "MIRROR%d", number);
GetPhysicalDevice(Temp, Physical);
strcpy(FileName, Physical);
strcat(FileName, ObjectFile);
if (FileExists(FileName))
{
SystemDebug.printf("***Located file on mirror device:%s instead of %s\n", Temp, Device);
return TRUE;
}
}
// for a jukebox device: try all other jukeboxes
if(strnicmp(Device, "JUKEBOX", 7)==0)
{
aSize = 0;
if(iniValuePtr->sscscpPtr->JUKEBOXDevicePtr != NULL )
aSize = iniValuePtr->sscscpPtr->JUKEBOXDevicePtr->GetSize();
for (i=0; i<aSize; i++)
{
if (i==(unsigned int)number) continue;
sprintf(Temp, "JUKEBOX%d", i);
if (sub1 >= 0) sprintf(Temp+strlen(Temp), ".%d", sub1);
GetPhysicalDevice(Temp, Physical);
strcpy(FileName, Physical);
strcat(FileName, ObjectFile);
if (FileExists(FileName))
{
SystemDebug.printf("***Located file on wrong device:%s instead of %s\n", Temp, Device);
return TRUE;
}
}
}
// for JUKEBOX try CACHE devices with jukebox number and sub1, e.g., from JUKEBOX1.123 tries CACHE0.1.123
if(strnicmp(Device, "JUKEBOX", 7)==0)
{
aSize = 0;
if(iniValuePtr->sscscpPtr->CACHEDevicePtr != NULL )
aSize = iniValuePtr->sscscpPtr->CACHEDevicePtr->GetSize();
for (i=0; i<aSize; i++)
{
sprintf(Temp, "CACHE%d", i);
if (number>= 0) sprintf(Temp+strlen(Temp), ".%d", number);
if (sub1 >= 0) sprintf(Temp+strlen(Temp), ".%d", sub1);
GetPhysicalDevice(Temp, Physical);
strcpy(FileName, Physical);
strcat(FileName, ObjectFile);
if (FileExists(FileName))
{
SystemDebug.printf("***Located file on wrong device:%s instead of %s\n", Temp, Device);
return TRUE;