Skip to content

Commit f7162f1

Browse files
committed
Merge pull request #13 from jayunit100/master
Fixes for Permissions and Secuirty Exceptions [MERGE]
2 parents 9b24072 + 38a220d commit f7162f1

File tree

5 files changed

+328
-63
lines changed

5 files changed

+328
-63
lines changed

README

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,6 @@ INSTALLATION
4444

4545
# ls target/
4646
classes glusterfs-0.20.2-0.1.jar maven-archiver surefire-reports test-classes
47-
^^^^^^^^^^^^^^^^^^
4847

4948
Copy the plugin to lib/ directory in your $HADOOP_HOME dir.
5049

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
package org.apache.hadoop.fs.glusterfs;
2+
3+
import java.io.DataInputStream;
4+
import java.io.IOException;
5+
import java.util.Map;
6+
import java.util.TreeMap;
7+
8+
/**
9+
* Because java 6 doesn't support cross platform file info, we use Runtime exec
10+
* to get details.
11+
*
12+
* This class will be extended in the future to also return permissions.
13+
*/
14+
public class FileInfoUtil {
15+
16+
/**
17+
* Returns the array of values from ls -aFl :
18+
*
19+
* Currently only handles "owner" , since that is what is most needed by
20+
* the GFAPI that is meant to use this class.
21+
*
22+
* m = getLSinfo("myfile.txt").get("owner")
23+
* System.out.println(m) ; <-- jayunit100
24+
*/
25+
public static Map<String, String> getLSinfo(String filename) throws IOException {
26+
String ret="";
27+
try {
28+
String ls_str;
29+
Process ls_proc = Runtime.getRuntime().exec("/bin/ls -aFl " + filename);
30+
DataInputStream ls_in = new DataInputStream(
31+
ls_proc.getInputStream());
32+
try {
33+
//should only be one line if input is a file
34+
while ((ls_str = ls_in.readLine()) != null) {
35+
if(ls_str.length()<10)
36+
;
37+
else{
38+
ret+=(ls_str);
39+
}
40+
}
41+
}
42+
catch (IOException e) {
43+
throw new RuntimeException(e);
44+
}
45+
}
46+
catch (IOException e1) {
47+
throw new RuntimeException(e1);
48+
}
49+
//initialization to "" was only to make for clean appending.
50+
if(ret.equals(""))
51+
ret=null;
52+
53+
//Convenience: transform to map
54+
Map<String, String> mm = lsToMap(ret);
55+
return mm;
56+
}
57+
58+
/**
59+
* Converts the output of ls -aFl to a map :
60+
*
61+
* EXPECTED INPUT STRING:
62+
* -rwxr-xr-x. 1 root root 786 Mar 7 11:42 buildbranch_and_copyjartovms.sh*
63+
*
64+
* EXPECTED OUTPUT:
65+
* key="owner" -> the owner of the file (root)
66+
* key="permissions" -> the hadoop permissions on the file.
67+
*/
68+
private static Map<String, String> lsToMap(String ret) {
69+
String[] values = ret.split("\\s+");
70+
71+
Map<String,String> mm = new TreeMap();
72+
mm.put("owner", values[2]);
73+
74+
return mm;
75+
}
76+
77+
78+
}

src/main/java/org/apache/hadoop/fs/glusterfs/GlusterFileSystem.java

Lines changed: 160 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,13 @@
2121
* Implements the Hadoop FileSystem Interface to allow applications to store
2222
* files on GlusterFS and run Map/Reduce jobs on the data.
2323
*/
24-
2524
package org.apache.hadoop.fs.glusterfs;
2625

2726
import java.io.*;
2827
import java.net.*;
2928

29+
import java.util.StringTokenizer;
30+
import java.util.TreeMap;
3031
import java.util.regex.*;
3132

3233
import org.apache.hadoop.conf.Configuration;
@@ -39,8 +40,8 @@
3940
import org.apache.hadoop.fs.BlockLocation;
4041
import org.apache.hadoop.fs.permission.FsPermission;
4142
import org.apache.hadoop.util.Progressable;
42-
43-
import java.util.TreeMap;
43+
import org.apache.hadoop.util.Shell;
44+
import org.apache.hadoop.util.StringUtils;
4445

4546
/*
4647
* This package provides interface for hadoop jobs (incl. Map/Reduce)
@@ -83,23 +84,22 @@ public boolean FUSEMount(String volname, String server, String mount)
8384
boolean ret = true;
8485
int retVal = 0;
8586
Process p = null;
87+
String s = null;
8688
String mountCmd = null;
8789

88-
mountCmd = "mount -t glusterfs " + server + ":" + "/" + volname + " "+ mount;
89-
System.out.println("Running: " + mountCmd);
90+
mountCmd = "mount -t glusterfs " + server + ":" + "/" + volname + " "
91+
+ mount;
92+
System.out.println(mountCmd);
9093
try {
9194
p = Runtime.getRuntime().exec(mountCmd);
92-
9395
retVal = p.waitFor();
9496
if (retVal != 0)
9597
ret = false;
9698
}
9799
catch (IOException e) {
98-
e.printStackTrace();
99-
System.out.println("Error calling mount, Continuing.., hopefully its already been mounted.");
100-
//throw new RuntimeException("Problem mounting FUSE mount on: "+ mount);
100+
System.out.println("Problem mounting FUSE mount on: " + mount);
101+
throw new RuntimeException(e);
101102
}
102-
103103
return ret;
104104
}
105105

@@ -122,20 +122,29 @@ public void initialize(URI uri, Configuration conf) throws IOException {
122122
needQuickRead = conf.get("quick.slave.io", null);
123123
autoMount = conf.getBoolean("fs.glusterfs.automount", true);
124124

125+
/*
126+
* bail out if we do not have enough information to do a FUSE mount
127+
*/
125128
if ((volName.length() == 0) || (remoteGFSServer.length() == 0)
126129
|| (glusterMount.length() == 0))
127-
throw new RuntimeException("Not enough info to mount FUSE: volname="+volName + " glustermount=" + glusterMount);
128-
129-
130-
if (autoMount) {
131-
ret = FUSEMount(volName, remoteGFSServer, glusterMount);
132-
if (!ret) {
133-
throw new RuntimeException("Initialize: Failed to mount GlusterFS ");
134-
}
135-
}
136-
137-
if((needQuickRead.length() != 0)
138-
&& (needQuickRead.equalsIgnoreCase("yes")
130+
throw new RuntimeException(
131+
"Not enough info for FUSE Mount : volname=" + volName
132+
+ ",server=" + remoteGFSServer
133+
+ ",glustermount=" + glusterMount);
134+
135+
ret = FUSEMount(volName, remoteGFSServer, glusterMount);
136+
137+
if (!ret) {
138+
throw new RuntimeException("Failed to init Gluster FS");
139+
}
140+
if (autoMount) {
141+
ret = FUSEMount(volName, remoteGFSServer, glusterMount);
142+
if (!ret) {
143+
throw new RuntimeException("Initialize: Failed to mount GlusterFS ");
144+
}
145+
}
146+
if((needQuickRead.length() != 0)
147+
&& (needQuickRead.equalsIgnoreCase("yes")
139148
|| needQuickRead.equalsIgnoreCase("on") || needQuickRead
140149
.equals("1")))
141150
this.quickSlaveIO = true;
@@ -153,8 +162,7 @@ public void initialize(URI uri, Configuration conf) throws IOException {
153162
setConf(conf);
154163
}
155164
catch (Exception e) {
156-
e.printStackTrace();
157-
throw new RuntimeException("Unable to initialize GlusterFS " + e.getMessage());
165+
throw new RuntimeException(e);
158166
}
159167
}
160168

@@ -199,13 +207,14 @@ public boolean exists(Path path) throws IOException {
199207
*/
200208
public boolean mkdirs(Path f, FsPermission permission) throws IOException {
201209

202-
if(f==null) return true;
203-
204-
Path parent = f.getParent();
205-
Path absolute = makeAbsolute(f);
206-
File p2f = new File(absolute.toUri().getPath());
207-
return (f == null || mkdirs(parent)) && (p2f.mkdir() || p2f.isDirectory());
208-
}
210+
if(f==null)
211+
return true;
212+
213+
Path parent = f.getParent();
214+
Path absolute = makeAbsolute(f);
215+
File p2f = new File(absolute.toUri().getPath());
216+
return (f == null || mkdirs(parent)) && (p2f.mkdir() || p2f.isDirectory());
217+
}
209218

210219
@Deprecated
211220
public boolean isDirectory(Path path) throws IOException {
@@ -274,31 +283,137 @@ public FileStatus getFileStatusFromFileString(String path)
274283
return getFileStatus(nPath);
275284
}
276285

286+
public static class FUSEFileStatus extends FileStatus {
287+
File theFile;
288+
289+
public FUSEFileStatus(File f) {
290+
super();
291+
theFile = f;
292+
}
293+
294+
public FUSEFileStatus(File f, boolean isdir, int block_replication,
295+
long blocksize, Path path) {
296+
// if its a dir, 0 length
297+
super(isdir ? 0 : f.length(), isdir, block_replication, blocksize,
298+
f.lastModified(), path);
299+
theFile = f;
300+
}
301+
302+
/**
303+
* Wrapper to "ls -aFL" - this should fix BZ908898
304+
*/
305+
@Override
306+
public String getOwner() {
307+
try {
308+
return FileInfoUtil.getLSinfo(theFile.getAbsolutePath()).
309+
get("owner");
310+
}
311+
catch (Exception e) {
312+
throw new RuntimeException(e);
313+
}
314+
}
315+
316+
public FsPermission getPermission() {
317+
//should be amortized, see method.
318+
loadPermissionInfo();
319+
return super.getPermission();
320+
}
321+
322+
boolean permsLoaded=false;
323+
324+
/// loads permissions, owner, and group from `ls -ld`
325+
private void loadPermissionInfo() {
326+
if (permsLoaded) {
327+
return;
328+
}
329+
IOException e = null;
330+
try {
331+
String output;
332+
StringTokenizer t = new StringTokenizer(
333+
output=execCommand(theFile,
334+
Shell.getGET_PERMISSION_COMMAND()));
335+
336+
//System.out.println("Output of PERMISSION command = " + output + " for " + this.getPath());
337+
//expected format
338+
//-rw------- 1 username groupname ...
339+
String permission = t.nextToken();
340+
if (permission.length() > 10) { //files with ACLs might have a '+'
341+
permission = permission.substring(0, 10);
342+
}
343+
setPermission(FsPermission.valueOf(permission));
344+
t.nextToken();
345+
setOwner(t.nextToken());
346+
setGroup(t.nextToken());
347+
} catch (Shell.ExitCodeException ioe) {
348+
if (ioe.getExitCode() != 1) {
349+
e = ioe;
350+
} else {
351+
setPermission(null);
352+
setOwner(null);
353+
setGroup(null);
354+
}
355+
permsLoaded=true;
356+
}
357+
catch (IOException ioe) {
358+
e = ioe;
359+
}
360+
finally {
361+
if (e != null) {
362+
throw new RuntimeException("Error while running command to get " +
363+
"file permissions : " +
364+
StringUtils.stringifyException(e));
365+
}
366+
}
367+
}
368+
369+
}
370+
371+
public static String execCommand(File f, String... cmd) throws IOException {
372+
String[] args = new String[cmd.length + 1];
373+
System.arraycopy(cmd, 0, args, 0, cmd.length);
374+
args[cmd.length] = f.getCanonicalPath();
375+
String output = Shell.execCommand(args);
376+
return output;
377+
}
378+
379+
/**
380+
* We ultimately use chmod to set permissions, same as in
381+
* https://svn.apache.org/repos/asf/hadoop/common/branches/HADOOP-3628/src/core/org/apache/hadoop/fs/RawLocalFileSystem.java
382+
*/
383+
@Override
384+
public void setPermission(Path p, FsPermission permission){
385+
try{
386+
Path absolute = makeAbsolute(p);
387+
final File f = new File(absolute.toUri().getPath());
388+
389+
execCommand(f, Shell.SET_PERMISSION_COMMAND,
390+
String.format("%05o", permission.toShort()));
391+
}
392+
catch(Exception e){
393+
throw new RuntimeException(e);
394+
}
395+
}
396+
397+
277398
public FileStatus getFileStatus(Path path) throws IOException {
278399
Path absolute = makeAbsolute(path);
279-
File f = new File(absolute.toUri().getPath());
400+
final File f = new File(absolute.toUri().getPath());
280401

281402
if (!f.exists())
282403
throw new FileNotFoundException("File " + f.getPath()
283404
+ " does not exist.");
284-
285405
FileStatus fs;
406+
286407
// simple version - should work . we'll see.
408+
// TODO COMPARE these w/ original signatures - do we retain the correct
409+
// default args?
287410
if (f.isDirectory())
288-
fs = new FileStatus(0, true, 1, 0, f.lastModified(),
289-
path.makeQualified(this)) {
290-
public String getOwner() {
291-
return "root";
292-
}
293-
};
411+
fs = new FUSEFileStatus(f, true, 1, 0, path.makeQualified(this));
294412
else
295-
fs = new FileStatus(f.length(), false, 0, getDefaultBlockSize(),
296-
f.lastModified(), path.makeQualified(this)) {
297-
public String getOwner() {
298-
return "root";
299-
}
300-
};
413+
fs = new FUSEFileStatus(f, false, 0, getDefaultBlockSize(),
414+
path.makeQualified(this));
301415
return fs;
416+
302417
}
303418

304419
/*

0 commit comments

Comments
 (0)