@Test public void testMkdirsFailsForSubdirectoryOfExistingFile() throws Exception { Path testDir = qualifiedPath("test/hadoop", fc2); Assert.assertFalse(exists(fc2, testDir)); fc2.mkdir(testDir, FsPermission.getDefault(), true); Assert.assertTrue(exists(fc2, testDir)); // Create file on fc1 using fc2 context createFile(fc1, qualifiedPath("test/hadoop/file", fc2)); Path testSubDir = qualifiedPath("test/hadoop/file/subdir", fc2); try { fc1.mkdir(testSubDir, FsPermission.getDefault(), true); Assert.fail("Should throw IOException."); } catch (IOException e) { // expected } Assert.assertFalse(exists(fc1, testSubDir)); Path testDeepSubDir = qualifiedPath("test/hadoop/file/deep/sub/dir", fc1); try { fc2.mkdir(testDeepSubDir, FsPermission.getDefault(), true); Assert.fail("Should throw IOException."); } catch (IOException e) { // expected } Assert.assertFalse(exists(fc1, testDeepSubDir)); }
@Test public void testDeleteMissing() { TaskAttemptContext taskAttemptContext = getTaskAttemptContext(config); JobContext jobContext = new JobContextImpl( taskAttemptContext.getConfiguration(), taskAttemptContext.getTaskAttemptID().getJobID()); Configuration conf = jobContext.getConfiguration(); String sourceBase; String targetBase; FileSystem fs = null; try { OutputCommitter committer = new CopyCommitter(null, taskAttemptContext); fs = FileSystem.get(conf); sourceBase = TestDistCpUtils.createTestSetup(fs, FsPermission.getDefault()); targetBase = TestDistCpUtils.createTestSetup(fs, FsPermission.getDefault()); String targetBaseAdd = TestDistCpUtils.createTestSetup(fs, FsPermission.getDefault()); fs.rename(new Path(targetBaseAdd), new Path(targetBase)); DistCpOptions options = new DistCpOptions(Arrays.asList(new Path(sourceBase)), new Path("/out")); options.setSyncFolder(true); options.setDeleteMissing(true); options.appendToConf(conf); CopyListing listing = new GlobbedCopyListing(conf, CREDENTIALS); Path listingFile = new Path("/tmp1/" + String.valueOf(rand.nextLong())); listing.buildListing(listingFile, options); conf.set(DistCpConstants.CONF_LABEL_TARGET_WORK_PATH, targetBase); conf.set(DistCpConstants.CONF_LABEL_TARGET_FINAL_PATH, targetBase); committer.commitJob(jobContext); if (!TestDistCpUtils.checkIfFoldersAreInSync(fs, targetBase, sourceBase)) { Assert.fail("Source and target folders are not in sync"); } if (!TestDistCpUtils.checkIfFoldersAreInSync(fs, sourceBase, targetBase)) { Assert.fail("Source and target folders are not in sync"); } // Test for idempotent commit committer.commitJob(jobContext); if (!TestDistCpUtils.checkIfFoldersAreInSync(fs, targetBase, sourceBase)) { Assert.fail("Source and target folders are not in sync"); } if (!TestDistCpUtils.checkIfFoldersAreInSync(fs, sourceBase, targetBase)) { Assert.fail("Source and target folders are not in sync"); } } catch (Throwable e) { LOG.error("Exception encountered while testing for delete missing", e); Assert.fail("Delete missing failure"); } finally { TestDistCpUtils.delete(fs, "/tmp1"); conf.set(DistCpConstants.CONF_LABEL_DELETE_MISSING, "false"); } }
/** * Convert IGFS file attributes into Hadoop permission. * * @param file File info. * @return Hadoop permission. */ private FsPermission permission(IgfsFile file) { String perm = file.property(IgfsUtils.PROP_PERMISSION, null); if (perm == null) return FsPermission.getDefault(); try { return new FsPermission((short) Integer.parseInt(perm, 8)); } catch (NumberFormatException ignore) { return FsPermission.getDefault(); } }
@Test public void testDeleteDirectory() throws IOException { String dirName = "dirTest"; Path testDirPath = qualifiedPath(dirName, fc2); // Ensure directory does not exist Assert.assertFalse(exists(fc2, testDirPath)); // Create a directory on fc2's file system using fc1 fc1.mkdir(testDirPath, FsPermission.getDefault(), true); // Ensure dir is created Assert.assertTrue(exists(fc2, testDirPath)); Assert.assertTrue(isDir(fc2, testDirPath)); fc2.delete(testDirPath, true); // Ensure that directory is deleted Assert.assertFalse(isDir(fc2, testDirPath)); // TestCase - Create and delete multiple directories String dirNames[] = { "deleteTest/testDir", "deleteTest/test Dir", "deleteTest/test*Dir", "deleteTest/test#Dir", "deleteTest/test1234", "deleteTest/1234Test", "deleteTest/test)Dir", "deleteTest/test_DIr", "deleteTest/()&^%$#@!~_+}{><?", " ", "^ " }; for (String f : dirNames) { // Create a file on fc2's file system using fc1 Path testPath = qualifiedPath(f, fc2); // Ensure file does not exist Assert.assertFalse(exists(fc2, testPath)); // Now create directory fc1.mkdir(testPath, FsPermission.getDefault(), true); // Ensure fc2 has the created directory Assert.assertTrue(exists(fc2, testPath)); Assert.assertTrue(isDir(fc2, testPath)); // Delete dir Assert.assertTrue(fc2.delete(testPath, true)); // verify if directory is deleted Assert.assertFalse(exists(fc2, testPath)); Assert.assertFalse(isDir(fc2, testPath)); } }
void generateInputs(int[] ignore) throws IOException { int nrDatanodes = getNumDatanodes(); int nrBlocks = (int) Math.ceil((double) blocksPerReport * nrDatanodes / replication); int nrFiles = (int) Math.ceil((double) nrBlocks / blocksPerFile); datanodes = new TinyDatanode[nrDatanodes]; // create data-nodes String prevDNName = ""; for (int idx = 0; idx < nrDatanodes; idx++) { datanodes[idx] = new TinyDatanode(idx, blocksPerReport); datanodes[idx].register(); assert datanodes[idx].getName().compareTo(prevDNName) > 0 : "Data-nodes must be sorted lexicographically."; datanodes[idx].sendHeartbeat(); prevDNName = datanodes[idx].getName(); } // create files LOG.info("Creating " + nrFiles + " with " + blocksPerFile + " blocks each."); FileNameGenerator nameGenerator; nameGenerator = new FileNameGenerator(getBaseDir(), 100); String clientName = getClientName(007); nameNode.setSafeMode(FSConstants.SafeModeAction.SAFEMODE_LEAVE); for (int idx = 0; idx < nrFiles; idx++) { String fileName = nameGenerator.getNextFileName("ThroughputBench"); nameNode.create( fileName, FsPermission.getDefault(), clientName, true, replication, BLOCK_SIZE); addBlocks(fileName, clientName); nameNode.complete(fileName, clientName); } // prepare block reports for (int idx = 0; idx < nrDatanodes; idx++) { datanodes[idx].formBlockReport(); } }
/** * 지정한 경로를 생성한다. * * @param fs FileSystem * @param path 생성할 경로 * @return 정상적으로 생성한 경우 <tt>true</tt> */ public static boolean mkdir(FileSystem fs, String path) { try { return FileSystem.mkdirs(fs, new Path(path), FsPermission.getDefault()); } catch (Exception ex) { throw new FileSystemException(ExceptionUtils.getMessage("Cannot create '{}'", path), ex); } }
@Test public void testDeleteNonExistingDirectory() throws IOException { String testDirName = "testFile"; Path testPath = qualifiedPath(testDirName, fc2); // TestCase1 : Test delete on directory never existed // Ensure directory does not exist Assert.assertFalse(exists(fc2, testPath)); // Delete on non existing directory should return false Assert.assertFalse(fc2.delete(testPath, false)); // TestCase2 : Create dir, Delete dir, Delete dir // Create a file on fc2's file system using fc1 fc1.mkdir(testPath, FsPermission.getDefault(), true); // Ensure dir exist Assert.assertTrue(exists(fc2, testPath)); // Delete test file, deleting existing file should return true Assert.assertTrue(fc2.delete(testPath, false)); // Ensure file does not exist Assert.assertFalse(exists(fc2, testPath)); // Delete on non existing file should return false Assert.assertFalse(fc2.delete(testPath, false)); }
/** * A stream obtained via this call must be closed before using other APIs of this class or else * the invocation will block. */ public FSDataOutputStream create( Path file, FsPermission permission, boolean overwrite, int bufferSize, short replication, long blockSize, Progressable progress) throws IOException { final FTPClient client = connect(); Path workDir = new Path(client.printWorkingDirectory()); Path absolute = makeAbsolute(workDir, file); if (exists(client, file)) { if (overwrite) { delete(client, file); } else { disconnect(client); throw new IOException("File already exists: " + file); } } Path parent = absolute.getParent(); if (parent == null || !mkdirs(client, parent, FsPermission.getDefault())) { parent = (parent == null) ? new Path("/") : parent; disconnect(client); throw new IOException("create(): Mkdirs failed to create: " + parent); } client.allocate(bufferSize); // Change to parent directory on the server. Only then can we write to the // file on the server by opening up an OutputStream. As a side effect the // working directory on the server is changed to the parent directory of the // file. The FTP client connection is closed when close() is called on the // FSDataOutputStream. client.changeWorkingDirectory(parent.toUri().getPath()); FSDataOutputStream fos = new FSDataOutputStream(client.storeFileStream(file.getName()), statistics) { public void close() throws IOException { super.close(); if (!client.isConnected()) { throw new FTPException("Client not connected"); } boolean cmdCompleted = client.completePendingCommand(); disconnect(client); if (!cmdCompleted) { throw new FTPException( "Could not complete transfer, Reply Code - " + client.getReplyCode()); } } }; if (!FTPReply.isPositivePreliminary(client.getReplyCode())) { // The ftpClient is an inconsistent state. Must close the stream // which in turn will logout and disconnect from FTP server fos.close(); throw new IOException("Unable to create file: " + file + ", Aborting"); } return fos; }
public BaseDataPublisher(State state) throws IOException { super(state); this.closer = Closer.create(); Configuration conf = new Configuration(); // Add all job configuration properties so they are picked up by Hadoop for (String key : this.getState().getPropertyNames()) { conf.set(key, this.getState().getProp(key)); } this.numBranches = this.getState().getPropAsInt(ConfigurationKeys.FORK_BRANCHES_KEY, 1); this.fileSystemByBranches = Lists.newArrayListWithCapacity(this.numBranches); this.publisherFinalDirOwnerGroupsByBranches = Lists.newArrayListWithCapacity(this.numBranches); this.permissions = Lists.newArrayListWithCapacity(this.numBranches); // Get a FileSystem instance for each branch for (int i = 0; i < this.numBranches; i++) { URI uri = URI.create( this.getState() .getProp( ForkOperatorUtils.getPropertyNameForBranch( ConfigurationKeys.WRITER_FILE_SYSTEM_URI, this.numBranches, i), ConfigurationKeys.LOCAL_FS_URI)); this.fileSystemByBranches.add(FileSystem.get(uri, conf)); // The group(s) will be applied to the final publisher output directory(ies) this.publisherFinalDirOwnerGroupsByBranches.add( Optional.fromNullable( this.getState() .getProp( ForkOperatorUtils.getPropertyNameForBranch( ConfigurationKeys.DATA_PUBLISHER_FINAL_DIR_GROUP, this.numBranches, i)))); // The permission(s) will be applied to all directories created by the publisher, // which do NOT include directories created by the writer and moved by the publisher. // The permissions of those directories are controlled by writer.file.permissions and // writer.dir.permissions. this.permissions.add( new FsPermission( state.getPropAsShortWithRadix( ForkOperatorUtils.getPropertyNameForBranch( ConfigurationKeys.DATA_PUBLISHER_PERMISSIONS, numBranches, i), FsPermission.getDefault().toShort(), ConfigurationKeys.PERMISSION_PARSING_RADIX))); } this.parallelRunnerThreads = state.getPropAsInt( ParallelRunner.PARALLEL_RUNNER_THREADS_KEY, ParallelRunner.DEFAULT_PARALLEL_RUNNER_THREADS); }
/** Do file create. */ long executeOp(int daemonId, int inputIdx, String clientName) throws IOException { long start = System.currentTimeMillis(); // dummyActionNoSynch(fileIdx); nameNode.create( fileNames[daemonId][inputIdx], FsPermission.getDefault(), clientName, true, replication, BLOCK_SIZE); long end = System.currentTimeMillis(); for (boolean written = !closeUponCreate; !written; written = nameNode.complete(fileNames[daemonId][inputIdx], clientName)) ; return end - start; }
// creates a file using DistributedFileSystem.createNonRecursive() static FSDataOutputStream createNonRecursive( FileSystem fs, Path name, int repl, boolean overwrite) throws IOException { System.out.println("createNonRecursive: Created " + name + " with " + repl + " replica."); FSDataOutputStream stm = ((DistributedFileSystem) fs) .createNonRecursive( name, FsPermission.getDefault(), overwrite, fs.getConf().getInt("io.file.buffer.size", 4096), (short) repl, (long) blockSize, null); return stm; }
/** * Convenience method, so that we don't open a new connection when using this method from within * another method. Otherwise every API invocation incurs the overhead of opening/closing a TCP * connection. */ private boolean mkdirs(FTPClient client, Path file, FsPermission permission) throws IOException { boolean created = true; Path workDir = new Path(client.printWorkingDirectory()); Path absolute = makeAbsolute(workDir, file); String pathName = absolute.getName(); if (!exists(client, absolute)) { Path parent = absolute.getParent(); created = (parent == null || mkdirs(client, parent, FsPermission.getDefault())); if (created) { String parentDir = parent.toUri().getPath(); client.changeWorkingDirectory(parentDir); created = created & client.makeDirectory(pathName); } } else if (isFile(client, absolute)) { throw new IOException( String.format("Can't make directory for path %s since it is a file.", absolute)); } return created; }
@Test public void testIsDirectory() throws IOException { String dirName = "dirTest"; String invalidDir = "nonExistantDir"; String rootDir = "/"; Path existingPath = qualifiedPath(dirName, fc2); Path nonExistingPath = qualifiedPath(invalidDir, fc2); Path pathToRootDir = qualifiedPath(rootDir, fc2); // Create a directory on fc2's file system using fc1 fc1.mkdir(existingPath, FsPermission.getDefault(), true); // Ensure fc2 has directory Assert.assertTrue(isDir(fc2, existingPath)); Assert.assertTrue(isDir(fc2, pathToRootDir)); // Negative test case Assert.assertFalse(isDir(fc2, nonExistingPath)); }
/** * Constructor * * @param length the number of bytes the file has * @param isdir if the path is a directory * @param block_replication the replication factor * @param blocksize the block size * @param modification_time modification time * @param access_time access time * @param permission permission * @param owner the owner of the path * @param group the group of the path * @param path the local name in java UTF8 encoding the same as that in-memory */ public HdfsFileStatus( long length, boolean isdir, int block_replication, long blocksize, long modification_time, long access_time, FsPermission permission, String owner, String group, byte[] path) { this.length = length; this.isdir = isdir; this.block_replication = (short) block_replication; this.blocksize = blocksize; this.modification_time = modification_time; this.access_time = access_time; this.permission = (permission == null) ? FsPermission.getDefault() : permission; this.owner = (owner == null) ? "" : owner; this.group = (group == null) ? "" : group; this.path = path; }
/** * Deprecated. Remains for legacy support. Should be removed when {@link Stat} gains support for * Windows and other operating systems. */ @Deprecated private FileStatus deprecatedGetFileLinkStatusInternal(final Path f) throws IOException { String target = FileUtil.readLink(new File(f.toString())); try { FileStatus fs = getFileStatus(f); // If f refers to a regular file or directory if (target.isEmpty()) { return fs; } // Otherwise f refers to a symlink return new FileStatus( fs.getLen(), false, fs.getReplication(), fs.getBlockSize(), fs.getModificationTime(), fs.getAccessTime(), fs.getPermission(), fs.getOwner(), fs.getGroup(), new Path(target), f); } catch (FileNotFoundException e) { /* The exists method in the File class returns false for dangling * links so we can get a FileNotFoundException for links that exist. * It's also possible that we raced with a delete of the link. Use * the readBasicFileAttributes method in java.nio.file.attributes * when available. */ if (!target.isEmpty()) { return new FileStatus( 0, false, 0, 0, 0, 0, FsPermission.getDefault(), "", "", new Path(target), f); } // f refers to a file or directory that does not exist throw e; } }
public FileStatus( long length, boolean isdir, int block_replication, long blocksize, long modification_time, long access_time, FsPermission permission, String owner, String group, Path symlink, Path path) { this.length = length; this.isdir = isdir; this.block_replication = (short) block_replication; this.blocksize = blocksize; this.modification_time = modification_time; this.access_time = access_time; if (permission != null) { this.permission = permission; } else if (isdir) { this.permission = FsPermission.getDirDefault(); } else if (symlink != null) { this.permission = FsPermission.getDefault(); } else { this.permission = FsPermission.getFileDefault(); } this.owner = (owner == null) ? "" : owner; this.group = (group == null) ? "" : group; this.symlink = symlink; this.path = path; // The variables isdir and symlink indicate the type: // 1. isdir implies directory, in which case symlink must be null. // 2. !isdir implies a file or symlink, symlink != null implies a // symlink, otherwise it's a file. assert (isdir && symlink == null) || !isdir; }
@Test public void testCreateDirectory() throws IOException { Path path = qualifiedPath("test/hadoop", fc2); Path falsePath = qualifiedPath("path/doesnot.exist", fc2); Path subDirPath = qualifiedPath("dir0", fc2); // Ensure that testPath does not exist in fc1 Assert.assertFalse(exists(fc1, path)); Assert.assertFalse(isFile(fc1, path)); Assert.assertFalse(isDir(fc1, path)); // Create a directory on fc2's file system using fc1 fc1.mkdir(path, FsPermission.getDefault(), true); // Ensure fc2 has directory Assert.assertTrue(isDir(fc2, path)); Assert.assertTrue(exists(fc2, path)); Assert.assertFalse(isFile(fc2, path)); // Test to create same dir twice, (HDFS mkdir is similar to mkdir -p ) fc1.mkdir(subDirPath, FsPermission.getDefault(), true); // This should not throw exception fc1.mkdir(subDirPath, FsPermission.getDefault(), true); // Create Sub Dirs fc1.mkdir(subDirPath, FsPermission.getDefault(), true); // Check parent dir Path parentDir = path.getParent(); Assert.assertTrue(exists(fc2, parentDir)); Assert.assertFalse(isFile(fc2, parentDir)); // Check parent parent dir Path grandparentDir = parentDir.getParent(); Assert.assertTrue(exists(fc2, grandparentDir)); Assert.assertFalse(isFile(fc2, grandparentDir)); // Negative test cases Assert.assertFalse(exists(fc2, falsePath)); Assert.assertFalse(isDir(fc2, falsePath)); // TestCase - Create multiple directories String dirNames[] = { "createTest/testDir", "createTest/test Dir", "deleteTest/test*Dir", "deleteTest/test#Dir", "deleteTest/test1234", "deleteTest/test_DIr", "deleteTest/1234Test", "deleteTest/test)Dir", "deleteTest/()&^%$#@!~_+}{><?", " ", "^ " }; for (String f : dirNames) { // Create a file on fc2's file system using fc1 Path testPath = qualifiedPath(f, fc2); // Ensure file does not exist Assert.assertFalse(exists(fc2, testPath)); // Now create directory fc1.mkdir(testPath, FsPermission.getDefault(), true); // Ensure fc2 has the created directory Assert.assertTrue(exists(fc2, testPath)); Assert.assertTrue(isDir(fc2, testPath)); } }
/** * Convert Hadoop permission into IGFS file attribute. * * @param perm Hadoop permission. * @return IGFS attributes. */ private Map<String, String> permission(FsPermission perm) { if (perm == null) perm = FsPermission.getDefault(); return F.asMap(IgfsUtils.PROP_PERMISSION, toString(perm)); }
@Test public void testListStatus() throws Exception { final String hPrefix = "test/hadoop"; final String[] dirs = { hPrefix + "/a", hPrefix + "/b", hPrefix + "/c", hPrefix + "/1", hPrefix + "/#@#@", hPrefix + "/&*#$#$@234" }; ArrayList<Path> testDirs = new ArrayList<Path>(); for (String d : dirs) { testDirs.add(qualifiedPath(d, fc2)); } Assert.assertFalse(exists(fc1, testDirs.get(0))); for (Path path : testDirs) { fc1.mkdir(path, FsPermission.getDefault(), true); } // test listStatus that returns an array of FileStatus FileStatus[] paths = fc1.util().listStatus(qualifiedPath("test", fc1)); Assert.assertEquals(1, paths.length); Assert.assertEquals(qualifiedPath(hPrefix, fc1), paths[0].getPath()); paths = fc1.util().listStatus(qualifiedPath(hPrefix, fc1)); Assert.assertEquals(6, paths.length); for (int i = 0; i < dirs.length; i++) { boolean found = false; for (int j = 0; j < paths.length; j++) { if (qualifiedPath(dirs[i], fc1).equals(paths[j].getPath())) { found = true; } } Assert.assertTrue(dirs[i] + " not found", found); } paths = fc1.util().listStatus(qualifiedPath(dirs[0], fc1)); Assert.assertEquals(0, paths.length); // test listStatus that returns an iterator of FileStatus RemoteIterator<FileStatus> pathsItor = fc1.listStatus(qualifiedPath("test", fc1)); Assert.assertEquals(qualifiedPath(hPrefix, fc1), pathsItor.next().getPath()); Assert.assertFalse(pathsItor.hasNext()); pathsItor = fc1.listStatus(qualifiedPath(hPrefix, fc1)); int dirLen = 0; for (; pathsItor.hasNext(); dirLen++) { boolean found = false; FileStatus stat = pathsItor.next(); for (int j = 0; j < dirs.length; j++) { if (qualifiedPath(dirs[j], fc1).equals(stat.getPath())) { found = true; break; } } Assert.assertTrue(stat.getPath() + " not found", found); } Assert.assertEquals(6, dirLen); pathsItor = fc1.listStatus(qualifiedPath(dirs[0], fc1)); Assert.assertFalse(pathsItor.hasNext()); }
/** * {@link HadoopFile} implementation for the HDFS protocol. * * @author Maxence Bernard */ public class HDFSFile extends HadoopFile { // TODO: allow a custom group to be set (see TODO below) // /** Name of the property holding the file's group */ // public static final String GROUP_PROPERTY_NAME = "group"; /** Default username */ private static String DEFAULT_USERNAME; /** Default group */ private static String DEFAULT_GROUP; /** Default file permissions */ private static final FilePermissions DEFAULT_PERMISSIONS = new SimpleFilePermissions( FsPermission.getDefault() .applyUMask(FsPermission.getUMask(DEFAULT_CONFIGURATION)) .toShort() & PermissionBits.FULL_PERMISSION_INT); static { try { UnixUserGroupInformation ugi = UnixUserGroupInformation.login(DEFAULT_CONFIGURATION); DEFAULT_USERNAME = ugi.getUserName(); // Do not use default groups, as these are pretty much useless } catch (Exception e) { // Should never happen but default to a reasonable value if it does DEFAULT_USERNAME = System.getProperty("user.name"); } DEFAULT_GROUP = DEFAULT_CONFIGURATION.get("dfs.permissions.supergroup", "supergroup"); } protected HDFSFile(FileURL url) throws IOException { super(url); } protected HDFSFile(FileURL url, FileSystem fs, FileStatus fileStatus) throws IOException { super(url, fs, fileStatus); } public static String getDefaultUsername() { return DEFAULT_USERNAME; } public static String getDefaultGroup() { return DEFAULT_GROUP; } private static String getUsername(FileURL url) { Credentials credentials = url.getCredentials(); String username; if (credentials == null || (username = credentials.getLogin()).equals("")) username = getDefaultUsername(); return username; } private static String getGroup(FileURL url) { // // Import the group from the URL's 'group' property, if set // String group = url.getProperty(GROUP_PROPERTY_NAME); // if(group==null || group.equals("")) // group = getDefaultGroup(); // // return group; return getDefaultGroup(); } /////////////////////////////// // HadoopFile implementation // /////////////////////////////// @Override protected FileSystem getHadoopFileSystem(FileURL url) throws IOException { // Note: getRealm returns a fresh instance every time FileURL realm = url.getRealm(); Configuration conf = new Configuration(); // Import the user from the URL's authority, if set // TODO: for some reason, setting the group has no effect: files are still created with the // default supergroup conf.setStrings(UnixUserGroupInformation.UGI_PROPERTY_NAME, getUsername(url), getGroup(url)); return FileSystem.get(URI.create(realm.toString(false)), conf); } @Override protected void setDefaultFileAttributes(FileURL url, HadoopFileAttributes atts) { atts.setOwner(getUsername(url)); atts.setGroup(getGroup(url)); atts.setPermissions(DEFAULT_PERMISSIONS); } }