AclEntryStatusFormat.java

/**
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.apache.hadoop.hdfs.server.namenode;

import java.util.List;

import org.apache.hadoop.fs.permission.AclEntry;
import org.apache.hadoop.fs.permission.AclEntryScope;
import org.apache.hadoop.fs.permission.AclEntryType;
import org.apache.hadoop.fs.permission.FsAction;
import org.apache.hadoop.hdfs.util.LongBitFormat;

/**
 * Class to pack an AclEntry into an integer. <br>
 * An ACL entry is represented by a 32-bit integer in Big Endian format. <br>
 *
 * Note:  this format is used both in-memory and on-disk.  Changes will be
 * incompatible.
 *
 */
public enum AclEntryStatusFormat implements LongBitFormat.Enum {

  PERMISSION(null, 3),
  TYPE(PERMISSION.BITS, 2),
  SCOPE(TYPE.BITS, 1),
  NAME(SCOPE.BITS, 24);

  private static final FsAction[] FSACTION_VALUES = FsAction.values();
  private static final AclEntryScope[] ACL_ENTRY_SCOPE_VALUES =
      AclEntryScope.values();
  private static final AclEntryType[] ACL_ENTRY_TYPE_VALUES =
      AclEntryType.values();

  private final LongBitFormat BITS;

  private AclEntryStatusFormat(LongBitFormat previous, int length) {
    BITS = new LongBitFormat(name(), previous, length, 0);
  }

  static AclEntryScope getScope(int aclEntry) {
    int ordinal = (int) SCOPE.BITS.retrieve(aclEntry);
    return ACL_ENTRY_SCOPE_VALUES[ordinal];
  }

  static AclEntryType getType(int aclEntry) {
    int ordinal = (int) TYPE.BITS.retrieve(aclEntry);
    return ACL_ENTRY_TYPE_VALUES[ordinal];
  }

  static FsAction getPermission(int aclEntry) {
    int ordinal = (int) PERMISSION.BITS.retrieve(aclEntry);
    return FSACTION_VALUES[ordinal];
  }

  static String getName(int aclEntry) {
    return getName(aclEntry, null);
  }

  static String getName(int aclEntry,
                        SerialNumberManager.StringTable stringTable) {
    SerialNumberManager snm = getSerialNumberManager(getType(aclEntry));
    if (snm != null) {
      int nid = (int)NAME.BITS.retrieve(aclEntry);
      return snm.getString(nid, stringTable);
    }
    return null;
  }

  static int toInt(AclEntry aclEntry) {
    long aclEntryInt = 0;
    aclEntryInt = SCOPE.BITS
        .combine(aclEntry.getScope().ordinal(), aclEntryInt);
    aclEntryInt = TYPE.BITS.combine(aclEntry.getType().ordinal(), aclEntryInt);
    aclEntryInt = PERMISSION.BITS.combine(aclEntry.getPermission().ordinal(),
        aclEntryInt);
    SerialNumberManager snm = getSerialNumberManager(aclEntry.getType());
    if (snm != null) {
      int nid = snm.getSerialNumber(aclEntry.getName());
      aclEntryInt = NAME.BITS.combine(nid, aclEntryInt);
    }
    return (int) aclEntryInt;
  }

  static AclEntry toAclEntry(int aclEntry) {
    return toAclEntry(aclEntry, null);
  }

  static AclEntry toAclEntry(int aclEntry,
                             SerialNumberManager.StringTable stringTable) {
    return new AclEntry.Builder()
        .setScope(getScope(aclEntry))
        .setType(getType(aclEntry))
        .setPermission(getPermission(aclEntry))
        .setName(getName(aclEntry, stringTable))
        .build();
  }

  public static int[] toInt(List<AclEntry> aclEntries) {
    int[] entries = new int[aclEntries.size()];
    for (int i = 0; i < entries.length; i++) {
      entries[i] = toInt(aclEntries.get(i));
    }
    return entries;
  }

  private static SerialNumberManager getSerialNumberManager(AclEntryType type) {
    switch (type) {
      case USER:
        return SerialNumberManager.USER;
      case GROUP:
        return SerialNumberManager.GROUP;
      default:
        return null;
    }
  }

  @Override
  public int getLength() {
    return BITS.getLength();
  }
}