-
+ F32079AAC09AC289E830F64803D3AAF2C0A31309900340D9548AF67FF86FE07741238BEED1E25741C33D2CB67C9AC8AFD4B23FA9B1E652CCBBEDDD0B50F1A31A
cryostat/libcryo/pmaps.adb
(0 . 0)(1 . 243)
563 ------------------------------------------------------------------------------
564 ------------------------------------------------------------------------------
565 -- This file is part of 'Cryostat', an Ada library for persistent storage. --
566 -- --
567 -- (C) 2020 Stanislav Datskovskiy ( www.loper-os.org ) --
568 -- http://wot.deedbot.org/17215D118B7239507FAFED98B98228A001ABFFC7.html --
569 -- --
570 -- You do not have, nor can you ever acquire the right to use, copy or --
571 -- distribute this software ; Should you use this software for any purpose, --
572 -- or copy and distribute it to anyone or in any manner, you are breaking --
573 -- the laws of whatever soi-disant jurisdiction, and you promise to --
574 -- continue doing so for the indefinite future. In any case, please --
575 -- always : read and understand any software ; verify any PGP signatures --
576 -- that you use - for any purpose. --
577 ------------------------------------------------------------------------------
578 ------------------------------------------------------------------------------
579
580 with System; use System;
581
582
583 package body PMaps is
584
585 -- Open a backing file at Path, with given params, for use with Initialize
586 function OpenMapFile(Path : in String;
587 Writable : in Boolean := False;
588 Create : in Boolean := False) return FD is
589
590 -- Buffer for converting the civilized Path string to a C-style string :
591 CPath : String(1 .. Path'Length + 1) := (others => Character'Val(0));
592
593 -- Unix FD handle for the backing file, obtained by Open()
594 FileFD : FD;
595
596 -- Flags provided to Open() -- default 'read only'
597 COpenFlag : O_Flags := O_RDONLY;
598
599 begin
600
601 -- Convert civilized string to the barbaric type expected by Open() :
602 CPath(Path'Range) := Path;
603
604 -- Set the writability flag for Open() if Writable is enabled :
605 if Writable then
606 COpenFlag := O_RDWR;
607 end if;
608
609 -- If file does not exist, and Create is enabled, it will be created :
610 if Create then
611 COpenFlag := COpenFlag or O_CREAT;
612 end if;
613
614 -- Open the file :
615 FileFD := Open(CPath'Address, COpenFlag);
616
617 -- If Open() failed, eggog :
618 if FileFD = FD_EGGOG then
619 raise PMapFailedOpen with "PMap: Failed to Open backing file";
620 end if;
621
622 -- Return the FD of the backing file :
623 return FileFD;
624
625 end OpenMapFile;
626
627
628 -- Initialize a new map
629 procedure Initialize(Map : in out PMap) is
630
631 -- Prot flags to be given to MMap()
632 MProtFlag : MM_Prot := PROT_READ;
633
634 -- Result code returned by FTruncate()
635 CErr : Unix_Int;
636
637 begin
638
639 -- Check that we have not already Open'd:
640 if Map.Status /= Stop then
641 Map.Status := Eggog;
642 raise PMapFailedOpen with "PMap: already Opened backing file";
643 end if;
644
645 -- If Write is enabled, set the appropriate flag for MMap() :
646 if Map.MapWritable then
647 MProtFlag := PROT_READ or PROT_WRITE;
648 end if;
649
650 -- If creating, pad the backing file to the payload size :
651 if Map.MapCreate then
652 CErr := FTruncate(Map.FileFD, Map.MapLength);
653 if CErr /= 0 then
654 Map.Status := Eggog;
655 raise PMapFailedOpen with "PMap: Failed to FTruncate backing file";
656 end if;
657 end if;
658
659 -- Ask the OS to set up the map itself:
660 Map.Address := MMap(Length => Map.MapLength,
661 Off_T => Map.MapOffset,
662 Prot => MProtFlag,
663 Flags => MAP_SHARED,
664 Handle => Map.FileFD);
665
666 -- Test for failure of MMap() call :
667 if Map.Address = MAP_FAILED then
668 Map.Status := Eggog;
669 raise PMapFailedMMap with "PMap: MAP_FAILED";
670 end if;
671
672 if Map.Address = NullPtr then
673 Map.Status := Eggog;
674 raise PMapFailedAddr with "PMap: Map Address is Null";
675 end if;
676
677 -- If no failure detected, mark the map as usable :
678 Map.Status := Run;
679
680 end Initialize;
681
682
683 -- Test whether a map is operating
684 function IsReady(Map : in PMap) return Boolean is
685 begin
686
687 return Map.Status = Run;
688
689 end IsReady;
690
691
692 -- Retrieve the memory address where the map payload resides
693 function GetAddress(Map : in PMap) return MapAddress is
694 begin
695
696 -- Ensure that the map is active :
697 if not IsReady(Map) then
698 raise PMapNotRunning with "PMap: GetAddress on inactive Map";
699 end if;
700
701 -- Return the address :
702 return Map.Address;
703
704 end GetAddress;
705
706
707 -- Zeroize the map, if it is writable
708 procedure Zap(Map : in out PMap) is
709
710 -- Represent the map's payload as a byte array across full length :
711 RawArray : array(1 .. Map.MapLength) of Byte;
712 for RawArray'Address use Map.Address;
713
714 begin
715
716 -- If map is inactive, do nothing :
717 if not IsReady(Map) then
718 return;
719 end if;
720
721 -- If tried to zap a read-only map, eggog :
722 if Map.MapWritable = False then
723 raise PMapNotWritable with "PMap: Tried to Zap a Read-Only Map";
724 end if;
725
726 -- Zeroize the payload of the map :
727 RawArray := (others => 0);
728
729 end Zap;
730
731
732 -- Sync the map to disk
733 procedure Sync(Map : in out PMap) is
734
735 -- Result code returned by MSync() and Close()
736 CErr : Unix_Int := 0;
737
738 begin
739
740 -- If map is inactive, do nothing :
741 if not IsReady(Map) then
742 return;
743 end if;
744
745 -- If map is writable, sync it to disk :
746 if Map.MapWritable then
747 CErr := MSync(Map.Address, Map.MapLength, MS_SYNC);
748 end if;
749
750 -- If eggog during MSync() :
751 if CErr /= 0 then
752 Map.Status := Eggog;
753 CErr := Close(Map.FileFD);
754 raise PMapFailedSync with "PMap: Failed to Sync";
755 end if;
756
757 end Sync;
758
759
760 -- Close map and mark it unusable
761 procedure Stop(Map : in out PMap) is
762
763 -- Result code returned by MUnmap() and Close()
764 CErr : Unix_Int;
765
766 begin
767
768 -- If map is already inactive, do nothing :
769 if not IsReady(Map) then
770 return;
771 end if;
772
773 -- Sync all changes to disk, if map was writable :
774 Sync(Map);
775
776 -- Mark map as inactive :
777 Map.Status := Stop;
778
779 -- Unmap the map :
780 CErr := MUnmap(Map.Address, Map.MapLength);
781 if CErr /= 0 then
782 Map.Status := Eggog;
783 raise PMapFailedUnmap with "PMap: Failed to Unmap";
784 end if;
785
786 -- Lastly, close out the FD :
787 CErr := Close(Map.FileFD);
788 if CErr /= 0 then
789 Map.Status := Eggog;
790 raise PMapFailedClose with "PMap: Failed to Close backing file";
791 end if;
792
793 end Stop;
794
795
796 -- Sync and close a given map, if fell out of scope
797 procedure Finalize(Map : in out PMap) is
798 begin
799
800 -- Close the map :
801 Stop(Map);
802
803 end Finalize;
804
805 end PMaps;