< 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,50 ****
--- 41,53 ----
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,379 ****
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
if (mtime != null)
e.mtime = mtime.toMillis();
if (atime != null)
e.atime = atime.toMillis();
if (ctime != null)
--- 372,382 ----
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
if (mtime != null)
e.mtime = mtime.toMillis();
if (atime != null)
e.atime = atime.toMillis();
if (ctime != null)
*** 382,391 ****
--- 385,415 ----
} 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,462 ****
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);
update(e);
} finally {
endWrite();
}
}
--- 476,486 ----
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, attrs);
update(e);
} finally {
endWrite();
}
}
*** 674,684 ****
}
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)));
} finally {
endRead();
}
} else {
--- 698,708 ----
}
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), attrs));
} finally {
endRead();
}
} else {
*** 739,749 ****
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);
if (forWrite) {
u.flag = FLAG_DATADESCR;
u.method = getCompressMethod(attrs);
}
// is there a better way to hook into the FileChannel's close method?
--- 763,773 ----
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, 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,1877 ****
--- 1892,1902 ----
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,1914 ****
this.size = 0;
this.csize = 0;
this.method = method;
}
! Entry(byte[] name, int type, boolean isdir, int method) {
this(name, isdir, method);
this.type = 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,1946 ----
this.size = 0;
this.csize = 0;
this.method = 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) {
name(e.name);
this.isdir = e.isdir;
this.version = e.version;
this.ctime = e.ctime;
this.atime = e.atime;
*** 1924,1949 ****
this.attrs = e.attrs;
this.attrsEx = e.attrsEx;
*/
this.locoff = e.locoff;
this.comment = e.comment;
this.type = type;
}
! Entry (byte[] name, Path file, int type) {
this(name, type, false, METHOD_STORED);
this.file = file;
}
! int version() throws ZipException {
if (method == METHOD_DEFLATED)
return 20;
else if (method == METHOD_STORED)
return 10;
throw new ZipException("unsupported compression method");
}
///////////////////// CEN //////////////////////
static Entry readCEN(ZipFileSystem zipfs, IndexNode inode)
throws IOException
{
return new Entry().cen(zipfs, inode);
--- 1956,2001 ----
this.attrs = e.attrs;
this.attrsEx = e.attrsEx;
*/
this.locoff = e.locoff;
this.comment = e.comment;
+ this.posixPerms = e.posixPerms;
this.type = 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(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,1979 ****
--- 2022,2034 ----
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,1999 ****
}
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)
--- 2044,2053 ----
*** 2020,2029 ****
--- 2074,2085 ----
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,2052 ****
} 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, flag); // general purpose bit flag
writeShort(os, method); // compression method
// last modification time
writeInt(os, (int)javaToDosTime(mtime));
writeInt(os, crc); // crc-32
--- 2092,2103 ----
} else { // Extended Timestamp otherwise
elenEXTT = 9; // only mtime in cen
}
}
writeInt(os, CENSIG); // CEN header signature
! 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,2073 ****
} 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, locoff0); // relative offset of local header
writeBytes(os, zname, 1, nlen);
! if (elen64 != 0) {
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)
--- 2111,2126 ----
} else {
writeShort(os, 0);
}
writeShort(os, 0); // starting disk number
writeShort(os, 0); // internal 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 (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,2123 ****
}
///////////////////// 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;
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, 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
--- 2155,2176 ----
}
///////////////////// LOC //////////////////////
int writeLOC(OutputStream os) throws IOException {
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, 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,2145 ****
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
}
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) {
writeInt(os, ZIP64_MINVAL);
writeInt(os, ZIP64_MINVAL);
} else {
writeInt(os, csize); // compressed size
writeInt(os, size); // uncompressed size
--- 2179,2197 ----
writeInt(os, 0);
writeInt(os, 0);
} else {
if (csize >= ZIP64_MINVAL || size >= ZIP64_MINVAL) {
elen64 = 20; //headid(2) + size(2) + size(8) + csize(8)
! 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 (zip64) {
writeInt(os, ZIP64_MINVAL);
writeInt(os, ZIP64_MINVAL);
} else {
writeInt(os, csize); // compressed size
writeInt(os, size); // uncompressed size
*** 2165,2175 ****
}
}
writeShort(os, nlen);
writeShort(os, elen + elen64 + elenNTFS + elenEXTT);
writeBytes(os, zname, 1, nlen);
! if (elen64 != 0) {
writeShort(os, EXTID_ZIP64);
writeShort(os, 16);
writeLong(os, size);
writeLong(os, csize);
}
--- 2217,2227 ----
}
}
writeShort(os, nlen);
writeShort(os, elen + elen64 + elenNTFS + elenEXTT);
writeBytes(os, zname, 1, nlen);
! if (zip64) {
writeShort(os, EXTID_ZIP64);
writeShort(os, 16);
writeLong(os, size);
writeLong(os, csize);
}
*** 2202,2212 ****
writeBytes(os, extra);
}
return LOCHDR + nlen + elen + elen64 + elenNTFS + elenEXTT;
}
! // Data Descriptior
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);
--- 2254,2264 ----
writeBytes(os, extra);
}
return LOCHDR + nlen + elen + elen64 + elenNTFS + elenEXTT;
}
! // 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,2411 ****
@Override
public Object fileKey() {
return null;
}
! ///////// zip entry attributes ///////////
public long compressedSize() {
return csize;
}
public long crc() {
return crc;
}
public int method() {
return method;
}
public byte[] extra() {
if (extra != null)
return Arrays.copyOf(extra, extra.length);
return null;
}
public byte[] comment() {
if (comment != null)
return Arrays.copyOf(comment, comment.length);
return null;
}
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());
--- 2429,2497 ----
@Override
public Object fileKey() {
return null;
}
! ///////// 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,2427 ****
--- 2504,2516 ----
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 >