jdk/src/solaris/classes/sun/nio/fs/UnixChannelFactory.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.channels.*;
       
    30 import java.io.FileDescriptor;
       
    31 import java.util.Set;
       
    32 
       
    33 import sun.nio.ch.FileChannelImpl;
       
    34 import sun.nio.ch.ThreadPool;
       
    35 import sun.nio.ch.SimpleAsynchronousFileChannelImpl;
       
    36 import sun.misc.SharedSecrets;
       
    37 import sun.misc.JavaIOFileDescriptorAccess;
       
    38 
       
    39 import com.sun.nio.file.ExtendedOpenOption;
       
    40 
       
    41 import static sun.nio.fs.UnixNativeDispatcher.*;
       
    42 import static sun.nio.fs.UnixConstants.*;
       
    43 
       
    44 /**
       
    45  * Factory for FileChannels and AsynchronousFileChannels
       
    46  */
       
    47 
       
    48 class UnixChannelFactory {
       
    49     private static final JavaIOFileDescriptorAccess fdAccess =
       
    50         SharedSecrets.getJavaIOFileDescriptorAccess();
       
    51 
       
    52     private UnixChannelFactory() {
       
    53     }
       
    54 
       
    55     /**
       
    56      * Represents the flags from a user-supplied set of open options.
       
    57      */
       
    58     private static class Flags {
       
    59         boolean read;
       
    60         boolean write;
       
    61         boolean append;
       
    62         boolean truncateExisting;
       
    63         boolean noFollowLinks;
       
    64         boolean create;
       
    65         boolean createNew;
       
    66         boolean deleteOnClose;
       
    67         boolean sync;
       
    68         boolean dsync;
       
    69 
       
    70         static Flags toFlags(Set<? extends OpenOption> options) {
       
    71             Flags flags = new Flags();
       
    72             for (OpenOption option: options) {
       
    73                 if (option instanceof StandardOpenOption) {
       
    74                     switch ((StandardOpenOption)option) {
       
    75                         case READ : flags.read = true; break;
       
    76                         case WRITE : flags.write = true; break;
       
    77                         case APPEND : flags.append = true; break;
       
    78                         case TRUNCATE_EXISTING : flags.truncateExisting = true; break;
       
    79                         case CREATE : flags.create = true; break;
       
    80                         case CREATE_NEW : flags.createNew = true; break;
       
    81                         case DELETE_ON_CLOSE : flags.deleteOnClose = true; break;
       
    82                         case SPARSE : /* ignore */ break;
       
    83                         case SYNC : flags.sync = true; break;
       
    84                         case DSYNC : flags.dsync = true; break;
       
    85                         default: throw new UnsupportedOperationException();
       
    86                     }
       
    87                     continue;
       
    88                 }
       
    89                 if (option == LinkOption.NOFOLLOW_LINKS) {
       
    90                     flags.noFollowLinks = true;
       
    91                     continue;
       
    92                 }
       
    93                 if (option == null)
       
    94                     throw new NullPointerException();
       
    95                throw new UnsupportedOperationException();
       
    96             }
       
    97             return flags;
       
    98         }
       
    99     }
       
   100 
       
   101 
       
   102     /**
       
   103      * Constructs a file channel from an existing (open) file descriptor
       
   104      */
       
   105     static FileChannel newFileChannel(int fd, boolean reading, boolean writing) {
       
   106         FileDescriptor fdObj = new FileDescriptor();
       
   107         fdAccess.set(fdObj, fd);
       
   108         return FileChannelImpl.open(fdObj, reading, writing, null);
       
   109     }
       
   110 
       
   111     /**
       
   112      * Constructs a file channel by opening a file using a dfd/path pair
       
   113      */
       
   114     static FileChannel newFileChannel(int dfd,
       
   115                                       UnixPath path,
       
   116                                       String pathForPermissionCheck,
       
   117                                       Set<? extends OpenOption> options,
       
   118                                       int mode)
       
   119         throws UnixException
       
   120     {
       
   121         Flags flags = Flags.toFlags(options);
       
   122 
       
   123         // default is reading; append => writing
       
   124         if (!flags.read && !flags.write) {
       
   125             if (flags.append) {
       
   126                 flags.write = true;
       
   127             } else {
       
   128                 flags.read = true;
       
   129             }
       
   130         }
       
   131 
       
   132         // validation
       
   133         if (flags.read && flags.append)
       
   134             throw new IllegalArgumentException("READ + APPEND not allowed");
       
   135         if (flags.append && flags.truncateExisting)
       
   136             throw new IllegalArgumentException("APPEND + TRUNCATE_EXISTING not allowed");
       
   137 
       
   138         FileDescriptor fdObj = open(dfd, path, pathForPermissionCheck, flags, mode);
       
   139         return FileChannelImpl.open(fdObj, flags.read, flags.write, null);
       
   140     }
       
   141 
       
   142     /**
       
   143      * Constructs a file channel by opening the given file.
       
   144      */
       
   145     static FileChannel newFileChannel(UnixPath path,
       
   146                                       Set<? extends OpenOption> options,
       
   147                                       int mode)
       
   148         throws UnixException
       
   149     {
       
   150         return newFileChannel(-1, path, null, options, mode);
       
   151     }
       
   152 
       
   153     /**
       
   154      * Constructs an asynchronous file channel by opening the given file.
       
   155      */
       
   156     static AsynchronousFileChannel newAsynchronousFileChannel(UnixPath path,
       
   157                                                               Set<? extends OpenOption> options,
       
   158                                                               int mode,
       
   159                                                               ThreadPool pool)
       
   160         throws UnixException
       
   161     {
       
   162         Flags flags = Flags.toFlags(options);
       
   163 
       
   164         // default is reading
       
   165         if (!flags.read && !flags.write) {
       
   166             flags.read = true;
       
   167         }
       
   168 
       
   169         // validation
       
   170         if (flags.append)
       
   171             throw new UnsupportedOperationException("APPEND not allowed");
       
   172 
       
   173         // for now use simple implementation
       
   174         FileDescriptor fdObj = open(-1, path, null, flags, mode);
       
   175         return SimpleAsynchronousFileChannelImpl.open(fdObj, flags.read, flags.write, pool);
       
   176     }
       
   177 
       
   178     /**
       
   179      * Opens file based on parameters and options, returning a FileDescriptor
       
   180      * encapsulating the handle to the open file.
       
   181      */
       
   182     static FileDescriptor open(int dfd,
       
   183                                UnixPath path,
       
   184                                String pathForPermissionCheck,
       
   185                                Flags flags,
       
   186                                int mode)
       
   187         throws UnixException
       
   188     {
       
   189         // map to oflags
       
   190         int oflags;
       
   191         if (flags.read && flags.write) {
       
   192             oflags = O_RDWR;
       
   193         } else {
       
   194             oflags = (flags.write) ? O_WRONLY : O_RDONLY;
       
   195         }
       
   196         if (flags.write) {
       
   197             if (flags.truncateExisting)
       
   198                 oflags |= O_TRUNC;
       
   199             if (flags.append)
       
   200                 oflags |= O_APPEND;
       
   201 
       
   202             // create flags
       
   203             if (flags.createNew) {
       
   204                 byte[] pathForSysCall = path.asByteArray();
       
   205 
       
   206                 // throw exception if file name is "." to avoid confusing error
       
   207                 if ((pathForSysCall[pathForSysCall.length-1] == '.') &&
       
   208                     (pathForSysCall.length == 1 ||
       
   209                     (pathForSysCall[pathForSysCall.length-2] == '/')))
       
   210                 {
       
   211                     throw new UnixException(EEXIST);
       
   212                 }
       
   213                 oflags |= (O_CREAT | O_EXCL);
       
   214             } else {
       
   215                 if (flags.create)
       
   216                     oflags |= O_CREAT;
       
   217             }
       
   218         }
       
   219 
       
   220         // follow links by default
       
   221         boolean followLinks = true;
       
   222         if (!flags.createNew && (flags.noFollowLinks || flags.deleteOnClose)) {
       
   223             followLinks = false;
       
   224             oflags |= O_NOFOLLOW;
       
   225         }
       
   226 
       
   227         if (flags.dsync)
       
   228             oflags |= O_DSYNC;
       
   229         if (flags.sync)
       
   230             oflags |= O_SYNC;
       
   231 
       
   232         // permission check before we open the file
       
   233         SecurityManager sm = System.getSecurityManager();
       
   234         if (sm != null) {
       
   235             if (pathForPermissionCheck == null)
       
   236                 pathForPermissionCheck = path.getPathForPermissionCheck();
       
   237             if (flags.read)
       
   238                 sm.checkRead(pathForPermissionCheck);
       
   239             if (flags.write)
       
   240                 sm.checkWrite(pathForPermissionCheck);
       
   241             if (flags.deleteOnClose)
       
   242                 sm.checkDelete(pathForPermissionCheck);
       
   243         }
       
   244 
       
   245         int fd;
       
   246         try {
       
   247             if (dfd >= 0) {
       
   248                 fd = openat(dfd, path.asByteArray(), oflags, mode);
       
   249             } else {
       
   250                 fd = UnixNativeDispatcher.open(path, oflags, mode);
       
   251             }
       
   252         } catch (UnixException x) {
       
   253             // Linux error can be EISDIR or EEXIST when file exists
       
   254             if (flags.createNew && (x.errno() == EISDIR)) {
       
   255                 x.setError(EEXIST);
       
   256             }
       
   257 
       
   258             // handle ELOOP to avoid confusing message
       
   259             if (!followLinks && (x.errno() == ELOOP)) {
       
   260                 x = new UnixException(x.getMessage() + " (NOFOLLOW_LINKS specified)");
       
   261             }
       
   262 
       
   263             throw x;
       
   264         }
       
   265 
       
   266         // unlink file immediately if delete on close. The spec is clear that
       
   267         // an implementation cannot guarantee to unlink the correct file when
       
   268         // replaced by an attacker after it is opened.
       
   269         if (flags.deleteOnClose) {
       
   270             try {
       
   271                 if (dfd >= 0) {
       
   272                     unlinkat(dfd, path.asByteArray(), 0);
       
   273                 } else {
       
   274                     unlink(path);
       
   275                 }
       
   276             } catch (UnixException ignore) {
       
   277                 // best-effort
       
   278             }
       
   279         }
       
   280 
       
   281         // create java.io.FileDescriptor
       
   282         FileDescriptor fdObj = new FileDescriptor();
       
   283         fdAccess.set(fdObj, fd);
       
   284         return fdObj;
       
   285     }
       
   286 }