< prev index next >
src/jdk.zipfs/share/classes/jdk/nio/zipfs/ZipFileSystem.java
Print this page
rev 53081 : 8213031: (zipfs) Add support for POSIX file permissions
Reviewed-by: simonis
@@ -41,10 +41,13 @@
import java.nio.channels.SeekableByteChannel;
import java.nio.channels.WritableByteChannel;
import java.nio.file.*;
import java.nio.file.attribute.FileAttribute;
import java.nio.file.attribute.FileTime;
+import java.nio.file.attribute.GroupPrincipal;
+import java.nio.file.attribute.PosixFilePermission;
+import java.nio.file.attribute.UserPrincipal;
import java.nio.file.attribute.UserPrincipalLookupService;
import java.nio.file.spi.FileSystemProvider;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.security.PrivilegedActionException;
@@ -369,11 +372,11 @@
ensureOpen();
Entry e = getEntry(path); // ensureOpen checked
if (e == null)
throw new NoSuchFileException(getString(path));
if (e.type == Entry.CEN)
- e.type = Entry.COPY; // copy e
+ e.type = Entry.COPY; // copy e
if (mtime != null)
e.mtime = mtime.toMillis();
if (atime != null)
e.atime = atime.toMillis();
if (ctime != null)
@@ -382,10 +385,31 @@
} finally {
endWrite();
}
}
+ void setPermissions(byte[] path, Set<PosixFilePermission> perms)
+ throws IOException
+ {
+ checkWritable();
+ beginWrite();
+ try {
+ ensureOpen();
+ Entry e = getEntry(path); // ensureOpen checked
+ if (e == null) {
+ throw new NoSuchFileException(getString(path));
+ }
+ if (e.type == Entry.CEN) {
+ e.type = Entry.COPY; // copy e
+ }
+ e.posixPerms = perms == null ? -1 : ZipUtils.permsToFlags(perms);
+ update(e);
+ } finally {
+ endWrite();
+ }
+ }
+
boolean exists(byte[] path)
throws IOException
{
beginRead();
try {
@@ -452,11 +476,11 @@
try {
ensureOpen();
if (dir.length == 0 || exists(dir)) // root dir, or exiting dir
throw new FileAlreadyExistsException(getString(dir));
checkParents(dir);
- Entry e = new Entry(dir, Entry.NEW, true, METHOD_STORED);
+ Entry e = new Entry(dir, Entry.NEW, true, METHOD_STORED, attrs);
update(e);
} finally {
endWrite();
}
}
@@ -674,11 +698,11 @@
}
if (!options.contains(CREATE) && !options.contains(CREATE_NEW))
throw new NoSuchFileException(getString(path));
checkParents(path);
return new EntryOutputChannel(
- new Entry(path, Entry.NEW, false, getCompressMethod(attrs)));
+ new Entry(path, Entry.NEW, false, getCompressMethod(attrs), attrs));
} finally {
endRead();
}
} else {
@@ -739,11 +763,11 @@
final boolean isFCH = (e != null && e.type == Entry.FILECH);
final Path tmpfile = isFCH ? e.file : getTempPathForEntry(path);
final FileChannel fch = tmpfile.getFileSystem()
.provider()
.newFileChannel(tmpfile, options, attrs);
- final Entry u = isFCH ? e : new Entry(path, tmpfile, Entry.FILECH);
+ final Entry u = isFCH ? e : new Entry(path, tmpfile, Entry.FILECH, attrs);
if (forWrite) {
u.flag = FLAG_DATADESCR;
u.method = getCompressMethod(attrs);
}
// is there a better way to hook into the FileChannel's close method?
@@ -1868,10 +1892,11 @@
int type = CEN; // default is the entry read from cen
// entry attributes
int version;
int flag;
+ int posixPerms = -1; // posix permissions
int method = -1; // compression method
long mtime = -1; // last modification time (in DOS time)
long atime = -1; // last access time
long ctime = -1; // create time
long crc = -1; // crc-32 of entry data
@@ -1899,16 +1924,23 @@
this.size = 0;
this.csize = 0;
this.method = method;
}
- Entry(byte[] name, int type, boolean isdir, int method) {
+ @SuppressWarnings("unchecked")
+ Entry(byte[] name, int type, boolean isdir, int method, FileAttribute<?>... attrs) {
this(name, isdir, method);
this.type = type;
+ for (FileAttribute<?> attr : attrs) {
+ String attrName = attr.name();
+ if (attrName.equals("posix:permissions") || attrName.equals("unix:permissions")) {
+ posixPerms = ZipUtils.permsToFlags((Set<PosixFilePermission>)attr.value());
+ }
+ }
}
- Entry (Entry e, int type) {
+ Entry(Entry e, int type) {
name(e.name);
this.isdir = e.isdir;
this.version = e.version;
this.ctime = e.ctime;
this.atime = e.atime;
@@ -1924,26 +1956,46 @@
this.attrs = e.attrs;
this.attrsEx = e.attrsEx;
*/
this.locoff = e.locoff;
this.comment = e.comment;
+ this.posixPerms = e.posixPerms;
this.type = type;
}
- Entry (byte[] name, Path file, int type) {
+ @SuppressWarnings("unchecked")
+ Entry(byte[] name, Path file, int type, FileAttribute<?>... attrs) {
this(name, type, false, METHOD_STORED);
this.file = file;
+ for (FileAttribute<?> attr : attrs) {
+ String attrName = attr.name();
+ if (attrName.equals("posix:permissions") || attrName.equals("unix:permissions")) {
+ posixPerms = ZipUtils.permsToFlags((Set<PosixFilePermission>)attr.value());
+ }
+ }
}
- int version() throws ZipException {
+ int version(boolean zip64) throws ZipException {
+ if (zip64) {
+ return 45;
+ }
if (method == METHOD_DEFLATED)
return 20;
else if (method == METHOD_STORED)
return 10;
throw new ZipException("unsupported compression method");
}
+ /**
+ * Adds information about compatibility of file attribute information
+ * to a version value.
+ */
+ int versionMadeBy(int version) {
+ return (posixPerms < 0) ? version :
+ VERSION_BASE_UNIX | (version & 0xff);
+ }
+
///////////////////// CEN //////////////////////
static Entry readCEN(ZipFileSystem zipfs, IndexNode inode)
throws IOException
{
return new Entry().cen(zipfs, inode);
@@ -1970,10 +2022,13 @@
versionMade = CENVEM(cen, pos);
disk = CENDSK(cen, pos);
attrs = CENATT(cen, pos);
attrsEx = CENATX(cen, pos);
*/
+ if (CENVEM_FA(cen, pos) == FILE_ATTRIBUTES_UNIX) {
+ posixPerms = CENATX_PERMS(cen, pos) & 0xFFF; // 12 bits for setuid, setgid, sticky + perms
+ }
locoff = CENOFF(cen, pos);
pos += CENHDR;
this.name = inode.name;
this.isdir = inode.isdir;
this.hashcode = inode.hashcode;
@@ -1989,11 +2044,10 @@
}
return this;
}
int writeCEN(OutputStream os) throws IOException {
- int version0 = version();
long csize0 = csize;
long size0 = size;
long locoff0 = locoff;
int elen64 = 0; // extra for ZIP64
int elenNTFS = 0; // extra for NTFS (a/c/mtime)
@@ -2020,10 +2074,12 @@
elen64 += 8; // offset(8)
}
if (elen64 != 0) {
elen64 += 4; // header and data sz 4 bytes
}
+ boolean zip64 = (elen64 != 0);
+ int version0 = version(zip64);
while (eoff + 4 < elen) {
int tag = SH(extra, eoff);
int sz = SH(extra, eoff + 2);
if (tag == EXTID_EXTT || tag == EXTID_NTFS) {
foundExtraTime = true;
@@ -2036,17 +2092,12 @@
} else { // Extended Timestamp otherwise
elenEXTT = 9; // only mtime in cen
}
}
writeInt(os, CENSIG); // CEN header signature
- if (elen64 != 0) {
- writeShort(os, 45); // ver 4.5 for zip64
- writeShort(os, 45);
- } else {
- writeShort(os, version0); // version made by
- writeShort(os, version0); // version needed to extract
- }
+ writeShort(os, versionMadeBy(version0)); // version made by
+ writeShort(os, version0); // version needed to extract
writeShort(os, flag); // general purpose bit flag
writeShort(os, method); // compression method
// last modification time
writeInt(os, (int)javaToDosTime(mtime));
writeInt(os, crc); // crc-32
@@ -2060,14 +2111,16 @@
} else {
writeShort(os, 0);
}
writeShort(os, 0); // starting disk number
writeShort(os, 0); // internal file attributes (unused)
- writeInt(os, 0); // external file attributes (unused)
+ writeInt(os, posixPerms > 0 ? posixPerms << 16 : 0); // external file
+ // attributes, used for storing posix
+ // permissions
writeInt(os, locoff0); // relative offset of local header
writeBytes(os, zname, 1, nlen);
- if (elen64 != 0) {
+ if (zip64) {
writeShort(os, EXTID_ZIP64);// Zip64 extra
writeShort(os, elen64 - 4); // size of "this" extra block
if (size0 == ZIP64_MINVAL)
writeLong(os, size);
if (csize0 == ZIP64_MINVAL)
@@ -2102,22 +2155,22 @@
}
///////////////////// LOC //////////////////////
int writeLOC(OutputStream os) throws IOException {
- int version0 = version();
byte[] zname = isdir ? toDirectoryPath(name) : name;
int nlen = (zname != null) ? zname.length - 1 : 0; // [0] is slash
int elen = (extra != null) ? extra.length : 0;
boolean foundExtraTime = false; // if extra timestamp present
int eoff = 0;
int elen64 = 0;
+ boolean zip64 = false;
int elenEXTT = 0;
int elenNTFS = 0;
writeInt(os, LOCSIG); // LOC header signature
if ((flag & FLAG_DATADESCR) != 0) {
- writeShort(os, version0); // version needed to extract
+ writeShort(os, version(zip64)); // version needed to extract
writeShort(os, flag); // general purpose bit flag
writeShort(os, method); // compression method
// last modification time
writeInt(os, (int)javaToDosTime(mtime));
// store size, uncompressed size, and crc-32 in data descriptor
@@ -2126,20 +2179,19 @@
writeInt(os, 0);
writeInt(os, 0);
} else {
if (csize >= ZIP64_MINVAL || size >= ZIP64_MINVAL) {
elen64 = 20; //headid(2) + size(2) + size(8) + csize(8)
- writeShort(os, 45); // ver 4.5 for zip64
- } else {
- writeShort(os, version0); // version needed to extract
+ zip64 = true;
}
+ writeShort(os, version(zip64)); // version needed to extract
writeShort(os, flag); // general purpose bit flag
writeShort(os, method); // compression method
// last modification time
writeInt(os, (int)javaToDosTime(mtime));
writeInt(os, crc); // crc-32
- if (elen64 != 0) {
+ if (zip64) {
writeInt(os, ZIP64_MINVAL);
writeInt(os, ZIP64_MINVAL);
} else {
writeInt(os, csize); // compressed size
writeInt(os, size); // uncompressed size
@@ -2165,11 +2217,11 @@
}
}
writeShort(os, nlen);
writeShort(os, elen + elen64 + elenNTFS + elenEXTT);
writeBytes(os, zname, 1, nlen);
- if (elen64 != 0) {
+ if (zip64) {
writeShort(os, EXTID_ZIP64);
writeShort(os, 16);
writeLong(os, size);
writeLong(os, csize);
}
@@ -2202,11 +2254,11 @@
writeBytes(os, extra);
}
return LOCHDR + nlen + elen + elen64 + elenNTFS + elenEXTT;
}
- // Data Descriptior
+ // Data Descriptor
int writeEXT(OutputStream os) throws IOException {
writeInt(os, EXTSIG); // EXT header signature
writeInt(os, crc); // crc-32
if (csize >= ZIP64_MINVAL || size >= ZIP64_MINVAL) {
writeLong(os, csize);
@@ -2377,35 +2429,69 @@
@Override
public Object fileKey() {
return null;
}
- ///////// zip entry attributes ///////////
+ ///////// posix file attributes ///////////
+
+ @Override
+ public UserPrincipal owner() {
+ throw new UnsupportedOperationException(
+ "ZipFileSystem does not support owner.");
+ }
+
+ @Override
+ public GroupPrincipal group() {
+ throw new UnsupportedOperationException(
+ "ZipFileSystem does not support group.");
+ }
+
+ @Override
+ public Set<PosixFilePermission> permissions() {
+ if (posixPerms == -1) {
+ // in case there are no Posix permissions associated with the
+ // entry, we should not return an empty set of permissions
+ // because that would be an explicit set of permissions meaning
+ // no permissions for anyone
+ throw new UnsupportedOperationException(
+ "No posix permissions associated with zip entry.");
+ }
+ return ZipUtils.permsFromFlags(posixPerms);
+ }
+
+ ///////// zip file attributes ///////////
+
+ @Override
public long compressedSize() {
return csize;
}
+ @Override
public long crc() {
return crc;
}
+ @Override
public int method() {
return method;
}
+ @Override
public byte[] extra() {
if (extra != null)
return Arrays.copyOf(extra, extra.length);
return null;
}
+ @Override
public byte[] comment() {
if (comment != null)
return Arrays.copyOf(comment, comment.length);
return null;
}
+ @Override
public String toString() {
StringBuilder sb = new StringBuilder(1024);
Formatter fm = new Formatter(sb);
fm.format(" name : %s%n", new String(name));
fm.format(" creationTime : %tc%n", creationTime().toMillis());
@@ -2418,10 +2504,13 @@
fm.format(" fileKey : %s%n", fileKey());
fm.format(" size : %d%n", size());
fm.format(" compressedSize : %d%n", compressedSize());
fm.format(" crc : %x%n", crc());
fm.format(" method : %d%n", method());
+ if (posixPerms != -1) {
+ fm.format(" permissions : %s%n", permissions());
+ }
fm.close();
return sb.toString();
}
}
< prev index next >