jdk/src/solaris/classes/sun/nio/fs/UnixSecureDirectoryStream.java
changeset 2057 3acf8e5e2ca0
child 3065 452aaa2899fc
equal deleted inserted replaced
2056:115e09b7a004 2057:3acf8e5e2ca0
       
     1 /*
       
     2  * Copyright 2008-2009 Sun Microsystems, Inc.  All Rights Reserved.
       
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
       
     4  *
       
     5  * This code is free software; you can redistribute it and/or modify it
       
     6  * under the terms of the GNU General Public License version 2 only, as
       
     7  * published by the Free Software Foundation.  Sun designates this
       
     8  * particular file as subject to the "Classpath" exception as provided
       
     9  * by Sun in the LICENSE file that accompanied this code.
       
    10  *
       
    11  * This code is distributed in the hope that it will be useful, but WITHOUT
       
    12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
       
    13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
       
    14  * version 2 for more details (a copy is included in the LICENSE file that
       
    15  * accompanied this code).
       
    16  *
       
    17  * You should have received a copy of the GNU General Public License version
       
    18  * 2 along with this work; if not, write to the Free Software Foundation,
       
    19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
       
    20  *
       
    21  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
       
    22  * CA 95054 USA or visit www.sun.com if you need additional information or
       
    23  * have any questions.
       
    24  */
       
    25 
       
    26 package sun.nio.fs;
       
    27 
       
    28 import java.nio.file.*;
       
    29 import java.nio.file.attribute.*;
       
    30 import java.nio.channels.SeekableByteChannel;
       
    31 import java.util.*;
       
    32 import java.util.concurrent.TimeUnit;
       
    33 import java.io.IOException;
       
    34 
       
    35 import static sun.nio.fs.UnixNativeDispatcher.*;
       
    36 import static sun.nio.fs.UnixConstants.*;
       
    37 
       
    38 /**
       
    39  * Unix implementation of SecureDirectoryStream.
       
    40  */
       
    41 
       
    42 class UnixSecureDirectoryStream
       
    43     extends SecureDirectoryStream
       
    44 {
       
    45     private final UnixDirectoryStream ds;
       
    46     private final int dfd;
       
    47 
       
    48     UnixSecureDirectoryStream(UnixPath dir,
       
    49                               long dp,
       
    50                               int dfd,
       
    51                               DirectoryStream.Filter<? super Path> filter)
       
    52     {
       
    53         this.ds = new UnixDirectoryStream(dir, dp, filter);
       
    54         this.dfd = dfd;
       
    55     }
       
    56 
       
    57     @Override
       
    58     public void close()
       
    59         throws IOException
       
    60     {
       
    61         ds.writeLock().lock();
       
    62         try {
       
    63             if (ds.closeImpl()) {
       
    64                 UnixNativeDispatcher.close(dfd);
       
    65             }
       
    66         } finally {
       
    67             ds.writeLock().unlock();
       
    68         }
       
    69     }
       
    70 
       
    71     @Override
       
    72     public Iterator<Path> iterator() {
       
    73         return ds.iterator(this);
       
    74     }
       
    75 
       
    76     private UnixPath getName(Path obj) {
       
    77         if (obj == null)
       
    78             throw new NullPointerException();
       
    79         if (!(obj instanceof UnixPath))
       
    80             throw new ProviderMismatchException();
       
    81         return (UnixPath)obj;
       
    82     }
       
    83 
       
    84     /**
       
    85      * Opens sub-directory in this directory
       
    86      */
       
    87     @Override
       
    88     public SecureDirectoryStream newDirectoryStream(Path obj,
       
    89                                                     boolean followLinks,
       
    90                                                     DirectoryStream.Filter<? super Path> filter)
       
    91         throws IOException
       
    92     {
       
    93         UnixPath file = getName(obj);
       
    94         UnixPath child = ds.directory().resolve(file);
       
    95 
       
    96         // permission check using name resolved against original path of directory
       
    97         SecurityManager sm = System.getSecurityManager();
       
    98         if (sm != null) {
       
    99             child.checkRead();
       
   100         }
       
   101 
       
   102         ds.readLock().lock();
       
   103         try {
       
   104             if (!ds.isOpen())
       
   105                 throw new ClosedDirectoryStreamException();
       
   106 
       
   107             // open directory and create new secure directory stream
       
   108             int newdfd1 = -1;
       
   109             int newdfd2 = -1;
       
   110             long ptr = 0L;
       
   111             try {
       
   112                 int flags = O_RDONLY;
       
   113                 if (!followLinks)
       
   114                     flags |= O_NOFOLLOW;
       
   115                 newdfd1 = openat(dfd, file.asByteArray(), flags , 0);
       
   116                 newdfd2 = dup(newdfd1);
       
   117                 ptr = fdopendir(newdfd1);
       
   118             } catch (UnixException x) {
       
   119                 if (newdfd1 != -1)
       
   120                     UnixNativeDispatcher.close(newdfd1);
       
   121                 if (newdfd2 != -1)
       
   122                     UnixNativeDispatcher.close(newdfd2);
       
   123                 if (x.errno() == UnixConstants.ENOTDIR)
       
   124                     throw new NotDirectoryException(file.toString());
       
   125                 x.rethrowAsIOException(file);
       
   126             }
       
   127             return new UnixSecureDirectoryStream(child, ptr, newdfd2, filter);
       
   128         } finally {
       
   129             ds.readLock().unlock();
       
   130         }
       
   131     }
       
   132 
       
   133     /**
       
   134      * Opens file in this directory
       
   135      */
       
   136     @Override
       
   137     public SeekableByteChannel newByteChannel(Path obj,
       
   138                                               Set<? extends OpenOption> options,
       
   139                                               FileAttribute<?>... attrs)
       
   140         throws IOException
       
   141     {
       
   142         UnixPath file = getName(obj);
       
   143 
       
   144         int mode = UnixFileModeAttribute
       
   145             .toUnixMode(UnixFileModeAttribute.ALL_READWRITE, attrs);
       
   146 
       
   147         // path for permission check
       
   148         String pathToCheck = ds.directory().resolve(file).getPathForPermissionCheck();
       
   149 
       
   150         ds.readLock().lock();
       
   151         try {
       
   152             if (!ds.isOpen())
       
   153                 throw new ClosedDirectoryStreamException();
       
   154             try {
       
   155                 return UnixChannelFactory.newFileChannel(dfd, file, pathToCheck, options, mode);
       
   156             } catch (UnixException x) {
       
   157                 x.rethrowAsIOException(file);
       
   158                 return null; // keep compiler happy
       
   159             }
       
   160         } finally {
       
   161             ds.readLock().unlock();
       
   162         }
       
   163     }
       
   164 
       
   165     /**
       
   166      * Deletes file/directory in this directory. Works in a race-free manner
       
   167      * when invoked with flags.
       
   168      */
       
   169     void implDelete(Path obj, boolean haveFlags, int flags)
       
   170         throws IOException
       
   171     {
       
   172         UnixPath file = getName(obj);
       
   173 
       
   174         // permission check using name resolved against original path of directory
       
   175         SecurityManager sm = System.getSecurityManager();
       
   176         if (sm != null) {
       
   177             ds.directory().resolve(file).checkDelete();
       
   178         }
       
   179 
       
   180         ds.readLock().lock();
       
   181         try {
       
   182             if (!ds.isOpen())
       
   183                 throw new ClosedDirectoryStreamException();
       
   184 
       
   185             if (!haveFlags) {
       
   186                 // need file attribute to know if file is directory. This creates
       
   187                 // a race in that the file may be replaced by a directory or a
       
   188                 // directory replaced by a file between the time we query the
       
   189                 // file type and unlink it.
       
   190                 UnixFileAttributes attrs = null;
       
   191                 try {
       
   192                     attrs = UnixFileAttributes.get(dfd, file, false);
       
   193                 } catch (UnixException x) {
       
   194                     x.rethrowAsIOException(file);
       
   195                 }
       
   196                 flags = (attrs.isDirectory()) ? AT_REMOVEDIR : 0;
       
   197             }
       
   198 
       
   199             try {
       
   200                 unlinkat(dfd, file.asByteArray(), flags);
       
   201             } catch (UnixException x) {
       
   202                 if ((flags & AT_REMOVEDIR) != 0) {
       
   203                     if (x.errno() == EEXIST || x.errno() == ENOTEMPTY) {
       
   204                         throw new DirectoryNotEmptyException(null);
       
   205                     }
       
   206                 }
       
   207                 x.rethrowAsIOException(file);
       
   208             }
       
   209         } finally {
       
   210             ds.readLock().unlock();
       
   211         }
       
   212     }
       
   213 
       
   214     @Override
       
   215     public void deleteFile(Path file) throws IOException {
       
   216         implDelete(file, true, 0);
       
   217     }
       
   218 
       
   219     @Override
       
   220     public void deleteDirectory(Path dir) throws IOException {
       
   221         implDelete(dir, true, AT_REMOVEDIR);
       
   222     }
       
   223 
       
   224     /**
       
   225      * Rename/move file in this directory to another (open) directory
       
   226      */
       
   227     @Override
       
   228     public void move(Path fromObj, SecureDirectoryStream dir, Path toObj)
       
   229         throws IOException
       
   230     {
       
   231         UnixPath from = getName(fromObj);
       
   232         UnixPath to = getName(toObj);
       
   233         if (dir == null)
       
   234             throw new NullPointerException();
       
   235         if (!(dir instanceof UnixSecureDirectoryStream))
       
   236             throw new ProviderMismatchException();
       
   237         UnixSecureDirectoryStream that = (UnixSecureDirectoryStream)dir;
       
   238 
       
   239         // permission check
       
   240         SecurityManager sm = System.getSecurityManager();
       
   241         if (sm != null) {
       
   242             this.ds.directory().resolve(from).checkWrite();
       
   243             that.ds.directory().resolve(to).checkWrite();
       
   244         }
       
   245 
       
   246         // lock ordering doesn't matter
       
   247         this.ds.readLock().lock();
       
   248         try {
       
   249             that.ds.readLock().lock();
       
   250             try {
       
   251                 if (!this.ds.isOpen() || !that.ds.isOpen())
       
   252                     throw new ClosedDirectoryStreamException();
       
   253                 try {
       
   254                     renameat(this.dfd, from.asByteArray(), that.dfd, to.asByteArray());
       
   255                 } catch (UnixException x) {
       
   256                     if (x.errno() == EXDEV) {
       
   257                         throw new AtomicMoveNotSupportedException(
       
   258                             from.toString(), to.toString(), x.errorString());
       
   259                     }
       
   260                     x.rethrowAsIOException(from, to);
       
   261                 }
       
   262             } finally {
       
   263                 that.ds.readLock().unlock();
       
   264             }
       
   265         } finally {
       
   266             this.ds.readLock().unlock();
       
   267         }
       
   268     }
       
   269 
       
   270     @SuppressWarnings("unchecked")
       
   271     private <V extends FileAttributeView> V getFileAttributeViewImpl(UnixPath file,
       
   272                                                                      Class<V> type,
       
   273                                                                      boolean followLinks)
       
   274     {
       
   275         if (type == null)
       
   276             throw new NullPointerException();
       
   277         Class<?> c = type;
       
   278         if (c == BasicFileAttributeView.class) {
       
   279             return (V) new BasicFileAttributeViewImpl(file, followLinks);
       
   280         }
       
   281         if (c == PosixFileAttributeView.class || c == FileOwnerAttributeView.class) {
       
   282             return (V) new PosixFileAttributeViewImpl(file, followLinks);
       
   283         }
       
   284         // TBD - should also support AclFileAttributeView
       
   285         return (V) null;
       
   286     }
       
   287 
       
   288     /**
       
   289      * Returns file attribute view bound to this directory
       
   290      */
       
   291     @Override
       
   292     public <V extends FileAttributeView> V getFileAttributeView(Class<V> type) {
       
   293         return getFileAttributeViewImpl(null, type, false);
       
   294     }
       
   295 
       
   296     /**
       
   297      * Returns file attribute view bound to dfd/filename.
       
   298      */
       
   299     @Override
       
   300     public <V extends FileAttributeView> V getFileAttributeView(Path obj,
       
   301                                                                 Class<V> type,
       
   302                                                                 LinkOption... options)
       
   303     {
       
   304         UnixPath file = getName(obj);
       
   305         boolean followLinks = file.getFileSystem().followLinks(options);
       
   306         return getFileAttributeViewImpl(file, type, followLinks);
       
   307     }
       
   308 
       
   309     /**
       
   310      * A BasicFileAttributeView implementation that using a dfd/name pair.
       
   311      */
       
   312     private class BasicFileAttributeViewImpl
       
   313         extends AbstractBasicFileAttributeView
       
   314     {
       
   315         final UnixPath file;
       
   316         final boolean followLinks;
       
   317 
       
   318         // set to true when binding to another object
       
   319         volatile boolean forwarding;
       
   320 
       
   321         BasicFileAttributeViewImpl(UnixPath file, boolean followLinks)
       
   322         {
       
   323             this.file = file;
       
   324             this.followLinks = followLinks;
       
   325         }
       
   326 
       
   327         int open() throws IOException {
       
   328             int oflags = O_RDONLY;
       
   329             if (!followLinks)
       
   330                 oflags |= O_NOFOLLOW;
       
   331             try {
       
   332                 return openat(dfd, file.asByteArray(), oflags, 0);
       
   333             } catch (UnixException x) {
       
   334                 x.rethrowAsIOException(file);
       
   335                 return -1; // keep compiler happy
       
   336             }
       
   337         }
       
   338 
       
   339         private void checkWriteAccess() {
       
   340             SecurityManager sm = System.getSecurityManager();
       
   341             if (sm != null) {
       
   342                 ds.directory().resolve(file).checkWrite();
       
   343             }
       
   344         }
       
   345 
       
   346         @Override
       
   347         public String name() {
       
   348             return "basic";
       
   349         }
       
   350 
       
   351         @Override
       
   352         public BasicFileAttributes readAttributes() throws IOException {
       
   353             ds.readLock().lock();
       
   354             try {
       
   355                 if (!ds.isOpen())
       
   356                     throw new ClosedDirectoryStreamException();
       
   357 
       
   358                 SecurityManager sm = System.getSecurityManager();
       
   359                 if (sm != null) {
       
   360                     if (file == null) {
       
   361                         ds.directory().checkRead();
       
   362                     } else {
       
   363                         ds.directory().resolve(file).checkRead();
       
   364                     }
       
   365                 }
       
   366                 try {
       
   367                      UnixFileAttributes attrs = (file == null) ?
       
   368                          UnixFileAttributes.get(dfd) :
       
   369                          UnixFileAttributes.get(dfd, file, followLinks);
       
   370 
       
   371                      // SECURITY: must return as BasicFileAttribute
       
   372                      return attrs.asBasicFileAttributes();
       
   373                 } catch (UnixException x) {
       
   374                     x.rethrowAsIOException(file);
       
   375                     return null;    // keep compiler happy
       
   376                 }
       
   377             } finally {
       
   378                 ds.readLock().unlock();
       
   379             }
       
   380         }
       
   381 
       
   382         @Override
       
   383         public void setTimes(Long lastModifiedTime,
       
   384                              Long lastAccessTime,
       
   385                              Long createTime, // ignore
       
   386                              TimeUnit unit)
       
   387             throws IOException
       
   388         {
       
   389             // no effect
       
   390             if (lastModifiedTime == null && lastAccessTime == null) {
       
   391                 return;
       
   392             }
       
   393 
       
   394             checkWriteAccess();
       
   395 
       
   396             ds.readLock().lock();
       
   397             try {
       
   398                 if (!ds.isOpen())
       
   399                     throw new ClosedDirectoryStreamException();
       
   400 
       
   401                 int fd = (file == null) ? dfd : open();
       
   402                 try {
       
   403                     UnixFileAttributes attrs = null;
       
   404 
       
   405                     // if not changing both attributes then need existing attributes
       
   406                     if (lastModifiedTime == null || lastAccessTime == null) {
       
   407                         try {
       
   408                             attrs = UnixFileAttributes.get(fd);
       
   409                         } catch (UnixException x) {
       
   410                             x.rethrowAsIOException(file);
       
   411                         }
       
   412                     }
       
   413 
       
   414                     // modified time = existing, now, or new value
       
   415                     long modTime;
       
   416                     if (lastModifiedTime == null) {
       
   417                         modTime = attrs.lastModifiedTime();
       
   418                     } else {
       
   419                         if (lastModifiedTime >= 0L) {
       
   420                             modTime = TimeUnit.MILLISECONDS.convert(lastModifiedTime, unit);
       
   421                         } else {
       
   422                             if (lastModifiedTime != -1L)
       
   423                                 throw new IllegalArgumentException();
       
   424                             modTime = System.currentTimeMillis();
       
   425                         }
       
   426                     }
       
   427 
       
   428                     // access time = existing, now, or new value
       
   429                     long accTime;
       
   430                     if (lastAccessTime == null) {
       
   431                         accTime = attrs.lastAccessTime();
       
   432                     } else {
       
   433                         if (lastAccessTime >= 0L) {
       
   434                             accTime = TimeUnit.MILLISECONDS.convert(lastAccessTime, unit);
       
   435                         } else {
       
   436                             if (lastAccessTime != -1L)
       
   437                                 throw new IllegalArgumentException();
       
   438                             accTime = System.currentTimeMillis();
       
   439                         }
       
   440                     }
       
   441 
       
   442                     try {
       
   443                         futimes(fd, accTime, modTime);
       
   444                     } catch (UnixException x) {
       
   445                         x.rethrowAsIOException(file);
       
   446                     }
       
   447                 } finally {
       
   448                     if (file != null)
       
   449                         UnixNativeDispatcher.close(fd);
       
   450                 }
       
   451             } finally {
       
   452                 ds.readLock().unlock();
       
   453             }
       
   454         }
       
   455     }
       
   456 
       
   457     /**
       
   458      * A PosixFileAttributeView implementation that using a dfd/name pair.
       
   459      */
       
   460     private class PosixFileAttributeViewImpl
       
   461         extends BasicFileAttributeViewImpl implements PosixFileAttributeView
       
   462     {
       
   463         private static final String PERMISSIONS_NAME = "permissions";
       
   464         private static final String OWNER_NAME = "owner";
       
   465         private static final String GROUP_NAME = "group";
       
   466 
       
   467         PosixFileAttributeViewImpl(UnixPath file, boolean followLinks) {
       
   468             super(file, followLinks);
       
   469         }
       
   470 
       
   471         private void checkWriteAndUserAccess() {
       
   472             SecurityManager sm = System.getSecurityManager();
       
   473             if (sm != null) {
       
   474                 super.checkWriteAccess();
       
   475                 sm.checkPermission(new RuntimePermission("accessUserInformation"));
       
   476             }
       
   477         }
       
   478 
       
   479         @Override
       
   480         public String name() {
       
   481             return "posix";
       
   482         }
       
   483 
       
   484         @Override
       
   485         public Object getAttribute(String attribute) throws IOException {
       
   486             if (attribute.equals(PERMISSIONS_NAME))
       
   487                 return readAttributes().permissions();
       
   488             if (attribute.equals(OWNER_NAME))
       
   489                 return readAttributes().owner();
       
   490             if (attribute.equals(GROUP_NAME))
       
   491                 return readAttributes().group();
       
   492             return super.getAttribute(attribute);
       
   493         }
       
   494 
       
   495         @Override
       
   496         @SuppressWarnings("unchecked")
       
   497         public void setAttribute(String attribute, Object value)
       
   498             throws IOException
       
   499         {
       
   500             if (attribute.equals(PERMISSIONS_NAME)) {
       
   501                 setPermissions((Set<PosixFilePermission>)value);
       
   502                 return;
       
   503             }
       
   504             if (attribute.equals(OWNER_NAME)) {
       
   505                 setOwner((UserPrincipal)value);
       
   506                 return;
       
   507             }
       
   508             if (attribute.equals(GROUP_NAME)) {
       
   509                 setGroup((GroupPrincipal)value);
       
   510                 return;
       
   511             }
       
   512             super.setAttribute(attribute, value);
       
   513         }
       
   514 
       
   515         final void addPosixAttributesToBuilder(PosixFileAttributes attrs,
       
   516                                                AttributesBuilder builder)
       
   517         {
       
   518             if (builder.match(PERMISSIONS_NAME))
       
   519                 builder.add(PERMISSIONS_NAME, attrs.permissions());
       
   520             if (builder.match(OWNER_NAME))
       
   521                 builder.add(OWNER_NAME, attrs.owner());
       
   522             if (builder.match(GROUP_NAME))
       
   523                 builder.add(GROUP_NAME, attrs.group());
       
   524         }
       
   525 
       
   526         @Override
       
   527         public Map<String,?> readAttributes(String first, String[] rest)
       
   528             throws IOException
       
   529         {
       
   530             AttributesBuilder builder = AttributesBuilder.create(first, rest);
       
   531             PosixFileAttributes attrs = readAttributes();
       
   532             addBasicAttributesToBuilder(attrs, builder);
       
   533             addPosixAttributesToBuilder(attrs, builder);
       
   534             return builder.unmodifiableMap();
       
   535         }
       
   536 
       
   537         @Override
       
   538         public PosixFileAttributes readAttributes() throws IOException {
       
   539             SecurityManager sm = System.getSecurityManager();
       
   540             if (sm != null) {
       
   541                 if (file == null)
       
   542                     ds.directory().checkRead();
       
   543                 else
       
   544                     ds.directory().resolve(file).checkRead();
       
   545                 sm.checkPermission(new RuntimePermission("accessUserInformation"));
       
   546             }
       
   547 
       
   548             ds.readLock().lock();
       
   549             try {
       
   550                 if (!ds.isOpen())
       
   551                     throw new ClosedDirectoryStreamException();
       
   552 
       
   553                 try {
       
   554                      UnixFileAttributes attrs = (file == null) ?
       
   555                          UnixFileAttributes.get(dfd) :
       
   556                          UnixFileAttributes.get(dfd, file, followLinks);
       
   557                      return attrs;
       
   558                 } catch (UnixException x) {
       
   559                     x.rethrowAsIOException(file);
       
   560                     return null;    // keep compiler happy
       
   561                 }
       
   562             } finally {
       
   563                 ds.readLock().unlock();
       
   564             }
       
   565         }
       
   566 
       
   567         @Override
       
   568         public void setPermissions(Set<PosixFilePermission> perms)
       
   569             throws IOException
       
   570         {
       
   571             // permission check
       
   572             checkWriteAndUserAccess();
       
   573 
       
   574             ds.readLock().lock();
       
   575             try {
       
   576                 if (!ds.isOpen())
       
   577                     throw new ClosedDirectoryStreamException();
       
   578 
       
   579                 int fd = (file == null) ? dfd : open();
       
   580                 try {
       
   581                     fchmod(fd, UnixFileModeAttribute.toUnixMode(perms));
       
   582                 } catch (UnixException x) {
       
   583                     x.rethrowAsIOException(file);
       
   584                 } finally {
       
   585                     if (file != null && fd >= 0)
       
   586                         UnixNativeDispatcher.close(fd);
       
   587                 }
       
   588             } finally {
       
   589                 ds.readLock().unlock();
       
   590             }
       
   591         }
       
   592 
       
   593         private void setOwners(int uid, int gid) throws IOException {
       
   594             // permission check
       
   595             checkWriteAndUserAccess();
       
   596 
       
   597             ds.readLock().lock();
       
   598             try {
       
   599                 if (!ds.isOpen())
       
   600                     throw new ClosedDirectoryStreamException();
       
   601 
       
   602                 int fd = (file == null) ? dfd : open();
       
   603                 try {
       
   604                     fchown(fd, uid, gid);
       
   605                 } catch (UnixException x) {
       
   606                     x.rethrowAsIOException(file);
       
   607                 } finally {
       
   608                     if (file != null && fd >= 0)
       
   609                         UnixNativeDispatcher.close(fd);
       
   610                 }
       
   611             } finally {
       
   612                 ds.readLock().unlock();
       
   613             }
       
   614         }
       
   615 
       
   616         @Override
       
   617         public UserPrincipal getOwner() throws IOException {
       
   618             return readAttributes().owner();
       
   619         }
       
   620 
       
   621         @Override
       
   622         public void setOwner(UserPrincipal owner)
       
   623             throws IOException
       
   624         {
       
   625             if (!(owner instanceof UnixUserPrincipals.User))
       
   626                 throw new ProviderMismatchException();
       
   627             if (owner instanceof UnixUserPrincipals.Group)
       
   628                 throw new IOException("'owner' parameter can't be a group");
       
   629             int uid = ((UnixUserPrincipals.User)owner).uid();
       
   630             setOwners(uid, -1);
       
   631         }
       
   632 
       
   633         @Override
       
   634         public void setGroup(GroupPrincipal group)
       
   635             throws IOException
       
   636         {
       
   637             if (!(group instanceof UnixUserPrincipals.Group))
       
   638                 throw new ProviderMismatchException();
       
   639             int gid = ((UnixUserPrincipals.Group)group).gid();
       
   640             setOwners(-1, gid);
       
   641         }
       
   642     }
       
   643 }