"Cryostat" (Genesis)

pmaps.adb


 1 ------------------------------------------------------------------------------
 2 ------------------------------------------------------------------------------
 3 -- This file is part of 'Cryostat', an Ada library for persistent storage. --
 4 -- --
 5 -- (C) 2020 Stanislav Datskovskiy ( www.loper-os.org ) --
 6 -- http://wot.deedbot.org/17215D118B7239507FAFED98B98228A001ABFFC7.html --
 7 -- --
 8 -- You do not have, nor can you ever acquire the right to use, copy or --
 9 -- distribute this software ; Should you use this software for any purpose, --
 10 -- or copy and distribute it to anyone or in any manner, you are breaking --
 11 -- the laws of whatever soi-disant jurisdiction, and you promise to --
 12 -- continue doing so for the indefinite future. In any case, please --
 13 -- always : read and understand any software ; verify any PGP signatures --
 14 -- that you use - for any purpose. --
 15 ------------------------------------------------------------------------------
 16 ------------------------------------------------------------------------------
 17 
 18 with System; use System;
 19 
 20 
 21 package body PMaps is
 22  
 23  -- Open a backing file at Path, with given params, for use with Initialize
 24  function OpenMapFile(Path : in String;
 25  Writable : in Boolean := False;
 26  Create : in Boolean := False) return FD is
 27  
 28  -- Buffer for converting the civilized Path string to a C-style string :
 29  CPath : String(1 .. Path'Length + 1) := (others => Character'Val(0));
 30  
 31  -- Unix FD handle for the backing file, obtained by Open()
 32  FileFD : FD;
 33  
 34  -- Flags provided to Open() -- default 'read only'
 35  COpenFlag : O_Flags := O_RDONLY;
 36  
 37  begin
 38  
 39  -- Convert civilized string to the barbaric type expected by Open() :
 40  CPath(Path'Range) := Path;
 41  
 42  -- Set the writability flag for Open() if Writable is enabled :
 43  if Writable then
 44  COpenFlag := O_RDWR;
 45  end if;
 46  
 47  -- If file does not exist, and Create is enabled, it will be created :
 48  if Create then
 49  COpenFlag := COpenFlag or O_CREAT;
 50  end if;
 51  
 52  -- Open the file :
 53  FileFD := Open(CPath'Address, COpenFlag);
 54  
 55  -- If Open() failed, eggog :
 56  if FileFD = FD_EGGOG then
 57  raise PMapFailedOpen with "PMap: Failed to Open backing file";
 58  end if;
 59  
 60  -- Return the FD of the backing file :
 61  return FileFD;
 62  
 63  end OpenMapFile;
 64  
 65  
 66  -- Initialize a new map
 67  procedure Initialize(Map : in out PMap) is
 68  
 69  -- Prot flags to be given to MMap()
 70  MProtFlag : MM_Prot := PROT_READ;
 71  
 72  -- Result code returned by FTruncate()
 73  CErr : Unix_Int;
 74  
 75  begin
 76  
 77  -- Check that we have not already Open'd:
 78  if Map.Status /= Stop then
 79  Map.Status := Eggog;
 80  raise PMapFailedOpen with "PMap: already Opened backing file";
 81  end if;
 82  
 83  -- If Write is enabled, set the appropriate flag for MMap() :
 84  if Map.MapWritable then
 85  MProtFlag := PROT_READ or PROT_WRITE;
 86  end if;
 87  
 88  -- If creating, pad the backing file to the payload size :
 89  if Map.MapCreate then
 90  CErr := FTruncate(Map.FileFD, Map.MapLength);
 91  if CErr /= 0 then
 92  Map.Status := Eggog;
 93  raise PMapFailedOpen with "PMap: Failed to FTruncate backing file";
 94  end if;
 95  end if;
 96  
 97  -- Ask the OS to set up the map itself:
 98  Map.Address := MMap(Length => Map.MapLength,
 99  Off_T => Map.MapOffset,
 100  Prot => MProtFlag,
 101  Flags => MAP_SHARED,
 102  Handle => Map.FileFD);
 103  
 104  -- Test for failure of MMap() call :
 105  if Map.Address = MAP_FAILED then
 106  Map.Status := Eggog;
 107  raise PMapFailedMMap with "PMap: MAP_FAILED";
 108  end if;
 109  
 110  if Map.Address = NullPtr then
 111  Map.Status := Eggog;
 112  raise PMapFailedAddr with "PMap: Map Address is Null";
 113  end if;
 114  
 115  -- If no failure detected, mark the map as usable :
 116  Map.Status := Run;
 117  
 118  end Initialize;
 119  
 120  
 121  -- Test whether a map is operating
 122  function IsReady(Map : in PMap) return Boolean is
 123  begin
 124  
 125  return Map.Status = Run;
 126  
 127  end IsReady;
 128  
 129  
 130  -- Retrieve the memory address where the map payload resides
 131  function GetAddress(Map : in PMap) return MapAddress is
 132  begin
 133  
 134  -- Ensure that the map is active :
 135  if not IsReady(Map) then
 136  raise PMapNotRunning with "PMap: GetAddress on inactive Map";
 137  end if;
 138  
 139  -- Return the address :
 140  return Map.Address;
 141  
 142  end GetAddress;
 143  
 144  
 145  -- Zeroize the map, if it is writable
 146  procedure Zap(Map : in out PMap) is
 147  
 148  -- Represent the map's payload as a byte array across full length :
 149  RawArray : array(1 .. Map.MapLength) of Byte;
 150  for RawArray'Address use Map.Address;
 151  
 152  begin
 153  
 154  -- If map is inactive, do nothing :
 155  if not IsReady(Map) then
 156  return;
 157  end if;
 158  
 159  -- If tried to zap a read-only map, eggog :
 160  if Map.MapWritable = False then
 161  raise PMapNotWritable with "PMap: Tried to Zap a Read-Only Map";
 162  end if;
 163  
 164  -- Zeroize the payload of the map :
 165  RawArray := (others => 0);
 166  
 167  end Zap;
 168  
 169  
 170  -- Sync the map to disk
 171  procedure Sync(Map : in out PMap) is
 172  
 173  -- Result code returned by MSync() and Close()
 174  CErr : Unix_Int := 0;
 175  
 176  begin
 177  
 178  -- If map is inactive, do nothing :
 179  if not IsReady(Map) then
 180  return;
 181  end if;
 182  
 183  -- If map is writable, sync it to disk :
 184  if Map.MapWritable then
 185  CErr := MSync(Map.Address, Map.MapLength, MS_SYNC);
 186  end if;
 187  
 188  -- If eggog during MSync() :
 189  if CErr /= 0 then
 190  Map.Status := Eggog;
 191  CErr := Close(Map.FileFD);
 192  raise PMapFailedSync with "PMap: Failed to Sync";
 193  end if;
 194  
 195  end Sync;
 196  
 197  
 198  -- Close map and mark it unusable
 199  procedure Stop(Map : in out PMap) is
 200  
 201  -- Result code returned by MUnmap() and Close()
 202  CErr : Unix_Int;
 203  
 204  begin
 205  
 206  -- If map is already inactive, do nothing :
 207  if not IsReady(Map) then
 208  return;
 209  end if;
 210  
 211  -- Sync all changes to disk, if map was writable :
 212  Sync(Map);
 213  
 214  -- Mark map as inactive :
 215  Map.Status := Stop;
 216  
 217  -- Unmap the map :
 218  CErr := MUnmap(Map.Address, Map.MapLength);
 219  if CErr /= 0 then
 220  Map.Status := Eggog;
 221  raise PMapFailedUnmap with "PMap: Failed to Unmap";
 222  end if;
 223  
 224  -- Lastly, close out the FD :
 225  CErr := Close(Map.FileFD);
 226  if CErr /= 0 then
 227  Map.Status := Eggog;
 228  raise PMapFailedClose with "PMap: Failed to Close backing file";
 229  end if;
 230  
 231  end Stop;
 232  
 233  
 234  -- Sync and close a given map, if fell out of scope
 235  procedure Finalize(Map : in out PMap) is
 236  begin
 237  
 238  -- Close the map :
 239  Stop(Map);
 240  
 241  end Finalize;
 242  
 243 end PMaps;

AltStyle によって変換されたページ (->オリジナル) /