FSDirectory implements Closeable { List<XAttr> setINodeXAttrs(final List<XAttr> existingXAttrs, final List<XAttr> toSet, final EnumSet<XAttrSetFlag> flag) throws IOException { for (int i = 0; i < toSet.size(); i++) { for (int j = i + 1; j < toSet.size(); j++) { if (toSet.get(i).equalsIgnoreValue(toSet.get(j))) { throw new IOException("Cannot specify the same XAttr to be set " + "more than once"); } } } int userVisibleXAttrsNum = 0; int newSize = (existingXAttrs != null) ? existingXAttrs.size() : 0; newSize += toSet.size(); List<XAttr> xAttrs = Lists.newArrayListWithCapacity(newSize); for (XAttr xAttr: toSet) { boolean exist = false; if (existingXAttrs != null) { for (XAttr a : existingXAttrs) { if (a.equalsIgnoreValue(xAttr)) { exist = true; break; } } } XAttrSetFlag.validate(xAttr.getName(), exist, flag); xAttrs.add(xAttr); if (isUserVisible(xAttr)) { userVisibleXAttrsNum++; } } if (existingXAttrs != null) { for (XAttr existing : existingXAttrs) { boolean alreadySet = false; for (XAttr set : toSet) { if (set.equalsIgnoreValue(existing)) { alreadySet = true; break; } } if (!alreadySet) { xAttrs.add(existing); if (isUserVisible(existing)) { userVisibleXAttrsNum++; } } } } if (userVisibleXAttrsNum > inodeXAttrsLimit) { throw new IOException("Cannot add additional XAttr to inode, " + "would exceed limit of " + inodeXAttrsLimit); } return xAttrs; } FSDirectory(FSNamesystem ns, Configuration conf); int getReadHoldCount(); int getWriteHoldCount(); INodeDirectory getRoot(); @Override void close(); INode getINode(String src); INodesInPath getLastINodeInPath(String src); INodesInPath getINodesInPath4Write(String src
      ); INode getINode4Write(String src); @VisibleForTesting long getYieldCount(); INodeMap getINodeMap(); final void addToInodeMap(INode inode); final void addRootDirToEncryptionZone(XAttrFeature xaf); final void removeFromInodeMap(List<? extends INode> inodes); INode getInode(long id); static byte[][] getPathComponents(INode inode); static boolean isReservedName(INode inode); static boolean isReservedName(String src); final static String DOT_RESERVED_STRING; final static String DOT_RESERVED_PATH_PREFIX; final static byte[] DOT_RESERVED; final static String DOT_INODES_STRING; final static byte[] DOT_INODES; @VisibleForTesting
  final EncryptionZoneManager ezManager; }
@Test public void testINodeXAttrsLimit() throws Exception { List<XAttr> existingXAttrs = Lists.newArrayListWithCapacity(2); XAttr xAttr1 = (new XAttr.Builder()).setNameSpace(XAttr.NameSpace.USER). setName("a1").setValue(new byte[]{0x31, 0x32, 0x33}).build(); XAttr xAttr2 = (new XAttr.Builder()).setNameSpace(XAttr.NameSpace.USER). setName("a2").setValue(new byte[]{0x31, 0x31, 0x31}).build(); existingXAttrs.add(xAttr1); existingXAttrs.add(xAttr2); XAttr newSystemXAttr = (new XAttr.Builder()). setNameSpace(XAttr.NameSpace.SYSTEM).setName("a3"). setValue(new byte[]{0x33, 0x33, 0x33}).build(); XAttr newRawXAttr = (new XAttr.Builder()).setNameSpace(XAttr.NameSpace.RAW). setName("a3").setValue(new byte[]{0x33, 0x33, 0x33}).build(); List<XAttr> newXAttrs = Lists.newArrayListWithCapacity(2); newXAttrs.add(newSystemXAttr); newXAttrs.add(newRawXAttr); List<XAttr> xAttrs = fsdir.setINodeXAttrs(existingXAttrs, newXAttrs, EnumSet.of(XAttrSetFlag.CREATE, XAttrSetFlag.REPLACE)); assertEquals(xAttrs.size(), 4); XAttr newXAttr1 = (new XAttr.Builder()).setNameSpace( XAttr.NameSpace.TRUSTED).setName("a4"). setValue(new byte[]{0x34, 0x34, 0x34}).build(); newXAttrs.set(0, newXAttr1); try { fsdir.setINodeXAttrs(existingXAttrs, newXAttrs, EnumSet.of(XAttrSetFlag.CREATE, XAttrSetFlag.REPLACE)); fail("Setting user visible xattr on inode should fail if " + "reaching limit."); } catch (IOException e) { GenericTestUtils.assertExceptionContains("Cannot add additional XAttr " + "to inode, would exceed limit", e); } }
@Test(timeout=300000) public void testXAttrMultiAddRemoveErrors() throws Exception { List<XAttr> existingXAttrs = Lists.newArrayList(); List<XAttr> toAdd = Lists.newArrayList(); toAdd.add(generatedXAttrs.get(0)); toAdd.add(generatedXAttrs.get(1)); toAdd.add(generatedXAttrs.get(2)); toAdd.add(generatedXAttrs.get(0)); try { fsdir.setINodeXAttrs(existingXAttrs, toAdd, EnumSet.of(XAttrSetFlag .CREATE)); fail("Specified the same xattr to be set twice"); } catch (IOException e) { GenericTestUtils.assertExceptionContains("Cannot specify the same " + "XAttr to be set", e); } toAdd.remove(generatedXAttrs.get(0)); existingXAttrs.add(generatedXAttrs.get(0)); try { fsdir.setINodeXAttrs(existingXAttrs, toAdd, EnumSet.of(XAttrSetFlag .CREATE)); fail("Set XAttr that is already set without REPLACE flag"); } catch (IOException e) { GenericTestUtils.assertExceptionContains("already exists", e); } try { fsdir.setINodeXAttrs(existingXAttrs, toAdd, EnumSet.of(XAttrSetFlag .REPLACE)); fail("Set XAttr that does not exist without the CREATE flag"); } catch (IOException e) { GenericTestUtils.assertExceptionContains("does not exist", e); } toAdd.remove(generatedXAttrs.get(0)); List<XAttr> newXAttrs = fsdir.setINodeXAttrs(existingXAttrs, toAdd, EnumSet.of(XAttrSetFlag.CREATE)); assertEquals("Unexpected toAdd size", 2, toAdd.size()); for (XAttr x : toAdd) { assertTrue("Did not find added XAttr " + x, newXAttrs.contains(x)); } existingXAttrs = newXAttrs; toAdd = Lists.newArrayList(); for (int i=0; i<3; i++) { XAttr xAttr = (new XAttr.Builder()) .setNameSpace(XAttr.NameSpace.SYSTEM) .setName("a" + i) .setValue(new byte[] { (byte) (i*2) }) .build(); toAdd.add(xAttr); } newXAttrs = fsdir.setINodeXAttrs(existingXAttrs, toAdd, EnumSet.of(XAttrSetFlag.REPLACE)); assertEquals("Unexpected number of new XAttrs", 3, newXAttrs.size()); for (int i=0; i<3; i++) { assertArrayEquals("Unexpected XAttr value", new byte[] {(byte)(i*2)}, newXAttrs.get(i).getValue()); } existingXAttrs = newXAttrs; toAdd = Lists.newArrayList(); for (int i=0; i<4; i++) { toAdd.add(generatedXAttrs.get(i)); } newXAttrs = fsdir.setINodeXAttrs(existingXAttrs, toAdd, EnumSet.of(XAttrSetFlag.CREATE, XAttrSetFlag.REPLACE)); verifyXAttrsPresent(newXAttrs, 4); }