PermissionInfoStorage.java

00001 /*
00002  * Copyright (c) 2006, KNOPFLERFISH project
00003  * All rights reserved.
00004  *
00005  * Redistribution and use in source and binary forms, with or without
00006  * modification, are permitted provided that the following
00007  * conditions are met:
00008  *
00009  * - Redistributions of source code must retain the above copyright
00010  *   notice, this list of conditions and the following disclaimer.
00011  *
00012  * - Redistributions in binary form must reproduce the above
00013  *   copyright notice, this list of conditions and the following
00014  *   disclaimer in the documentation and/or other materials
00015  *   provided with the distribution.
00016  *
00017  * - Neither the name of the KNOPFLERFISH project nor the names of its
00018  *   contributors may be used to endorse or promote products derived
00019  *   from this software without specific prior written permission.
00020  *
00021  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00022  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00023  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00024  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
00025  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00026  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
00027  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
00028  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00029  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
00030  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
00031  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
00032  * OF THE POSSIBILITY OF SUCH DAMAGE.
00033  */
00034 
00035 package org.knopflerfish.framework.permissions;
00036 
00037 import java.io.*;
00038 import java.security.*;
00039 import java.util.ArrayList;
00040 import java.util.HashMap;
00041 import java.util.Iterator;
00042 
00043 import org.osgi.service.permissionadmin.PermissionInfo;
00044 import org.knopflerfish.framework.Util;
00045 
00046 
00047 class PermissionInfoStorage {
00048 
00049   final static String DEFAULTPERM = "(java.security.AllPermission)";
00050 
00051   private PermissionInfo[] initialDefault = null;
00052 
00053   private File permDir;
00054 
00055   private long lastPermFile;
00056 
00057   private HashMap /* String -> Element */ permissions = new HashMap();
00058 
00059   private PermissionInfo[] defaultPermissions;
00060 
00061   private HashMap defaultInvalidateCallbacks = new HashMap();
00062 
00063 
00064   public PermissionInfoStorage() {
00065      initialDefault = new PermissionInfo[] { new PermissionInfo(DEFAULTPERM) };
00066      defaultPermissions = initialDefault;
00067 
00068      permDir = Util.getFileStorage("perms");
00069      if (permDir == null) {
00070        System.err.println("Property org.osgi.framework.dir not set," +
00071        "permission data will not be saved between sessions");
00072      } else {
00073        load();
00074      }
00075    }
00076 
00077 
00084   synchronized PermissionInfo[] get(String location, PermissionsWrapper callInvalidate) {
00085     Element res = (Element) permissions.get(location);
00086     if (res != null) {
00087       if (callInvalidate != null) {
00088         if (res.invalidateCallback == null) {
00089           res.invalidateCallback = new ArrayList(2);
00090         }
00091         res.invalidateCallback.add(callInvalidate);
00092       }
00093       return res.pi;
00094     }
00095     return null;
00096   }
00097 
00098 
00107   synchronized PermissionInfo[] getDefault(PermissionsWrapper callInvalidate) {
00108     if (callInvalidate != null) {
00109       ArrayList cil = (ArrayList)defaultInvalidateCallbacks.get(callInvalidate.location);
00110       if (cil == null) {
00111         cil = new ArrayList(2);
00112         defaultInvalidateCallbacks.put(callInvalidate.location, cil);
00113       }
00114       cil.add(callInvalidate);
00115     }
00116     return defaultPermissions;
00117   }
00118 
00119 
00127   synchronized String [] getKeys() {
00128     int size = permissions.size();
00129     if (size == 0) {
00130       return null;
00131     } else {
00132       String [] res = new String [size];
00133       int ix = 0;
00134       for (Iterator i = permissions.keySet().iterator(); i.hasNext();) {
00135         res[ix++] = (String)i.next();
00136       }
00137       return res;
00138     }
00139   }
00140 
00141 
00151   synchronized void put(String location, PermissionInfo[] perms) {
00152     Element old = (Element)permissions.put(location, new Element(perms));
00153     save(location, perms);
00154     ArrayList vpw = old != null ? old.invalidateCallback :
00155       (ArrayList)defaultInvalidateCallbacks.remove(location);
00156     if (vpw != null) {
00157       for (Iterator i = vpw.iterator(); i.hasNext(); ) {
00158         ((PermissionsWrapper)i.next()).invalidate();
00159       }
00160     }
00161   }
00162 
00163 
00176   synchronized void putDefault(PermissionInfo[] permissions) {
00177     if (permissions != null) {
00178       defaultPermissions = permissions;
00179     } else {
00180       defaultPermissions = initialDefault;
00181     }
00182     save(null, defaultPermissions);
00183     for (Iterator i = defaultInvalidateCallbacks.values().iterator(); i.hasNext(); ) {
00184       for (Iterator j = ((ArrayList)i.next()).iterator(); j.hasNext(); ) {
00185         ((PermissionsWrapper)j.next()).invalidate();
00186       }
00187     }
00188     defaultInvalidateCallbacks.clear();
00189   }
00190 
00191 
00198   synchronized void remove(String location) {
00199     Element old = (Element)permissions.remove(location);
00200     save(location, null);
00201     if (old != null && old.invalidateCallback != null) {
00202       for (Iterator i = old.invalidateCallback.iterator(); i.hasNext(); ) {
00203         ((PermissionsWrapper)i.next()).invalidate();
00204       }
00205     }
00206   }
00207 
00208 
00215   synchronized void purgeCallback(PermissionCollection pc) {
00216     PermissionsWrapper pw = (PermissionsWrapper)pc;
00217     Element e = (Element)permissions.get(pw.location);
00218     if (e != null && e.invalidateCallback != null && e.invalidateCallback.remove(pw)) {
00219       if (e.invalidateCallback.isEmpty()) {
00220         e.invalidateCallback = null;
00221       }
00222     } else {
00223       ArrayList cil = (ArrayList)defaultInvalidateCallbacks.get(pw.location);
00224       if (cil != null && cil.remove(pw)) {
00225         if (cil.isEmpty()) {
00226           defaultInvalidateCallbacks.remove(pw);
00227         }
00228       }
00229     }
00230   }
00231 
00232   //
00233   // Private methods
00234   //
00235 
00239   private void save(final String location, final PermissionInfo [] perms) {
00240     if (permDir != null) {
00241       AccessController.doPrivileged(new PrivilegedAction() {
00242           public Object run() {
00243             File f;
00244             String loc;
00245             if (location != null) {
00246               if (lastPermFile % 20 == 0) {
00247                 purge();
00248               }
00249               f = new File(permDir, Long.toString(++lastPermFile));
00250               loc = location;
00251             } else {
00252               // NYI! keep backups
00253               f = new File(permDir, "default");
00254               loc = "defaultPermissions";
00255             }
00256             BufferedWriter out = null;
00257             try {
00258               out = new BufferedWriter(new FileWriter(f));
00259               int p;
00260               while ((p = loc.indexOf('\n')) != -1) {
00261                 out.write(loc.substring(0, ++p) + " ");
00262                 loc = loc.substring(p);
00263               }
00264               out.write(loc + "\n\n");
00265               if (perms != null) {
00266                 for (int i = 0; i < perms.length; i++) {
00267                   out.write(perms[i].getEncoded() + "\n");
00268                 }
00269               } else {
00270                 out.write("NULL\n");
00271               }
00272               out.write("\n");
00273               out.close();
00274             } catch (IOException e) {
00275               if (out != null) {
00276                 try {
00277                   out.close();
00278                 } catch (IOException ignore) { }
00279                 f.delete();
00280               }
00281               // NYI! Report error
00282             }
00283             return null;
00284           }
00285         });
00286     }
00287   }
00288 
00289 
00293   private void load() {
00294     File[] files = getSortedFiles();
00295     for (int i = 0; i < files.length; i++) {
00296       load(files[i]);
00297     }
00298   }
00299 
00303   private void load(File fh) {
00304     BufferedReader in = null;
00305     boolean isDefault = "default".equals(fh.getName());
00306     try {
00307       in = new BufferedReader(new FileReader(fh));
00308       String loc = parseLocation(in);
00309       ArrayList piv = new ArrayList();
00310       // Read permissions
00311       int c = in.read();
00312       while (c != -1) {
00313         StringBuffer pe = new StringBuffer();
00314         while (c != -1 && c != (int)'\n') {
00315           pe.append((char) c);
00316           c = in.read();
00317         }
00318         String line = pe.toString();
00319         if ("NULL".equals(line)) {
00320           // Clear any previous entries
00321           if (isDefault) {
00322             defaultPermissions = null;
00323           } else {
00324             permissions.remove(loc);
00325           }
00326           try {
00327             in.close();
00328           } catch (IOException ignore) { }
00329           return;
00330         } else if ("".equals(line)) {
00331           // Correct end with double NL
00332           break;
00333         }
00334         piv.add(new PermissionInfo(line));
00335         c = in.read();
00336       }
00337       if (c == -1) {
00338         throw new IOException("Premature EOF when parsing permission file: " + fh.getName());
00339       }
00340       if (in.read() != -1) {
00341         throw new IOException("Garbage at end of file when parsing permission file: " + fh.getName());
00342       }
00343       in.close();
00344       PermissionInfo[] pi = new PermissionInfo[piv.size()];
00345       piv.toArray(pi);
00346       if (isDefault) {
00347         defaultPermissions = pi;
00348       } else {
00349         permissions.put(loc, new Element(pi));
00350       }
00351     } catch (IOException e) {
00352       if (in != null) {
00353         try {
00354           in.close();
00355         } catch (IOException ignore) { }
00356       }
00357       // NYI! Report error
00358     }
00359   }
00360 
00364   private String parseLocation(Reader in) throws IOException {
00365     StringBuffer loc = new StringBuffer();
00366     int c;
00367     // Read location
00368     while ((c = in.read()) != -1) {
00369       char cc = (char)c;
00370       if (cc == '\n') {
00371         c = in.read();
00372         if (c != (int)' ') {
00373           break;
00374         }
00375       }
00376       loc.append(cc);
00377     }
00378     return loc.toString();
00379   }
00380 
00385   private void purge() {
00386     HashMap foundTwo = new HashMap();
00387     File[] files = getSortedFiles();
00388     for (int i = files.length - 1; i >= 0; i--) {
00389       String loc;
00390       BufferedReader in = null;
00391       try {
00392         in = new BufferedReader(new FileReader(files[i]));
00393         loc = parseLocation(in);
00394       } catch (IOException ignore) {
00395         files[i].delete();
00396         continue;
00397       } finally {
00398         if (in != null) {
00399           try {
00400             in.close();
00401           } catch (IOException ignore) { }
00402         }
00403       }
00404       Boolean v = (Boolean)foundTwo.get(loc);
00405       if (v != null) {
00406         if (v.booleanValue()) {
00407           files[i].delete();
00408         } else {
00409           foundTwo.put(loc, new Boolean(true));
00410         }
00411       } else {
00412         foundTwo.put(loc, new Boolean(false));
00413       }
00414     }
00415   }
00416 
00421   private File[] getSortedFiles() {
00422     String[] files = permDir.list();
00423     File[] res = new File[files.length];
00424     long[] lfiles = new long[files.length];
00425     int lf = -1;
00426     int pos = 0;
00427     for (int i = 0; i < files.length; i++) {
00428       try {
00429         long fval = Long.parseLong(files[i]);
00430         int j;
00431         for (j = lf; j >= 0; j--) {
00432           if (fval > lfiles[j]) {
00433             break;
00434           }
00435         }
00436         if (j >= lf) {
00437           lfiles[++lf] = fval;
00438         } else {
00439           lf++;
00440           j++;
00441           System.arraycopy(lfiles, j, lfiles, j+1, lf-j);
00442           lfiles[j] = fval;
00443         }
00444         files[i] = null;
00445       } catch (NumberFormatException ignore) {
00446         res[pos++] = new File(permDir, files[i]);
00447       }
00448     }
00449     for (int i = 0; i <= lf; i++) {
00450       res[pos++] = new File(permDir, Long.toString(lfiles[i]));
00451     }
00452     lastPermFile = (lf >= 0) ? lfiles[lf] : -1;
00453     return res;
00454   }
00455 
00456   class Element {
00457     PermissionInfo[] pi;
00458     ArrayList /* PermissionsWrapper */ invalidateCallback = null;
00459 
00460     Element(PermissionInfo[] pi) {
00461       this.pi = pi;
00462     }
00463   }
00464 }

Generated on Mon Jan 11 21:19:16 2010 for OpenMobileIS by  doxygen 1.5.4