1 /* 2 * Copyright (c) 2008, 2009, Oracle and/or its affiliates. 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. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package sun.nio.fs; 27 28 29 import java.nio.file.attribute.*; 30 import java.util.*; 31 import java.io.IOException; 32 33 import static sun.nio.fs.WindowsNativeDispatcher.*; 34 import static sun.nio.fs.WindowsConstants.*; 35 36 class WindowsFileAttributeViews { 37 38 private static class Basic extends AbstractBasicFileAttributeView { 39 final WindowsPath file; 40 final boolean followLinks; 41 42 Basic(WindowsPath file, boolean followLinks) { 43 this.file = file; 44 this.followLinks = followLinks; 45 } 46 47 @Override 48 public WindowsFileAttributes readAttributes() throws IOException { 49 file.checkRead(); 50 try { 51 return WindowsFileAttributes.get(file, followLinks); 52 } catch (WindowsException x) { 53 x.rethrowAsIOException(file); 54 return null; // keep compiler happy 55 } 56 } 57 58 /** 59 * Adjusts a Windows time for the FAT epoch. 60 */ 61 private long adjustForFatEpoch(long time) { 62 // 1/1/1980 in Windows Time 63 final long FAT_EPOCH = 119600064000000000L; 64 if (time != -1L && time < FAT_EPOCH) { 65 return FAT_EPOCH; 66 } else { 67 return time; 68 } 69 } 70 71 /** 72 * Parameter values in Windows times. 73 */ 74 void setFileTimes(long createTime, 75 long lastAccessTime, 76 long lastWriteTime) 77 throws IOException 78 { 79 long handle = -1L; 80 try { 81 int flags = FILE_FLAG_BACKUP_SEMANTICS; 82 if (!followLinks && file.getFileSystem().supportsLinks()) 83 flags |= FILE_FLAG_OPEN_REPARSE_POINT; 84 85 handle = CreateFile(file.getPathForWin32Calls(), 86 FILE_WRITE_ATTRIBUTES, 87 (FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE), 88 OPEN_EXISTING, 89 flags); 90 } catch (WindowsException x) { 91 x.rethrowAsIOException(file); 92 } 93 94 // update times 95 try { 96 SetFileTime(handle, 97 createTime, 98 lastAccessTime, 99 lastWriteTime); 100 } catch (WindowsException x) { 101 // If ERROR_INVALID_PARAMATER is returned and the volume is 102 // FAT then adjust to the FAT epoch and retry. 103 if (followLinks && x.lastError() == ERROR_INVALID_PARAMATER) { 104 try { 105 if (WindowsFileStore.create(file).type().equals("FAT")) { 106 SetFileTime(handle, 107 adjustForFatEpoch(createTime), 108 adjustForFatEpoch(lastAccessTime), 109 adjustForFatEpoch(lastWriteTime)); 110 // retry succeeded 111 x = null; 112 } 113 } catch (SecurityException ignore) { 114 } catch (WindowsException ignore) { 115 } catch (IOException ignore) { 116 // ignore exceptions to let original exception be thrown 117 } 118 } 119 if (x != null) 120 x.rethrowAsIOException(file); 121 } finally { 122 CloseHandle(handle); 123 } 124 } 125 126 @Override 127 public void setTimes(FileTime lastModifiedTime, 128 FileTime lastAccessTime, 129 FileTime createTime) throws IOException 130 { 131 // if all null then do nothing 132 if (lastModifiedTime == null && lastAccessTime == null && 133 createTime == null) 134 { 135 // no effect 136 return; 137 } 138 139 // permission check 140 file.checkWrite(); 141 142 // update times 143 long t1 = (createTime == null) ? -1L : 144 WindowsFileAttributes.toWindowsTime(createTime); 145 long t2 = (lastAccessTime == null) ? -1L : 146 WindowsFileAttributes.toWindowsTime(lastAccessTime); 147 long t3 = (lastModifiedTime == null) ? -1L : 148 WindowsFileAttributes.toWindowsTime(lastModifiedTime); 149 setFileTimes(t1, t2, t3); 150 } 151 } 152 153 static class Dos extends Basic implements DosFileAttributeView { 154 private static final String READONLY_NAME = "readonly"; 155 private static final String ARCHIVE_NAME = "archive"; 156 private static final String SYSTEM_NAME = "system"; 157 private static final String HIDDEN_NAME = "hidden"; 158 private static final String ATTRIBUTES_NAME = "attributes"; 159 160 // the names of the DOS attribtues (includes basic) 161 static final Set<String> dosAttributeNames = 162 Util.newSet(basicAttributeNames, 163 READONLY_NAME, ARCHIVE_NAME, SYSTEM_NAME, HIDDEN_NAME, ATTRIBUTES_NAME); 164 165 Dos(WindowsPath file, boolean followLinks) { 166 super(file, followLinks); 167 } 168 169 @Override 170 public String name() { 171 return "dos"; 172 } 173 174 @Override 175 public void setAttribute(String attribute, Object value) 176 throws IOException 177 { 178 if (attribute.equals(READONLY_NAME)) { 179 setReadOnly((Boolean)value); 180 return; 181 } 182 if (attribute.equals(ARCHIVE_NAME)) { 183 setArchive((Boolean)value); 184 return; 185 } 186 if (attribute.equals(SYSTEM_NAME)) { 187 setSystem((Boolean)value); 188 return; 189 } 190 if (attribute.equals(HIDDEN_NAME)) { 191 setHidden((Boolean)value); 192 return; 193 } 194 super.setAttribute(attribute, value); 195 } 196 197 @Override 198 public Map<String,Object> readAttributes(String[] attributes) 199 throws IOException 200 { 201 AttributesBuilder builder = 202 AttributesBuilder.create(dosAttributeNames, attributes); 203 WindowsFileAttributes attrs = readAttributes(); 204 addRequestedBasicAttributes(attrs, builder); 205 if (builder.match(READONLY_NAME)) 206 builder.add(READONLY_NAME, attrs.isReadOnly()); 207 if (builder.match(ARCHIVE_NAME)) 208 builder.add(ARCHIVE_NAME, attrs.isArchive()); 209 if (builder.match(SYSTEM_NAME)) 210 builder.add(SYSTEM_NAME, attrs.isSystem()); 211 if (builder.match(HIDDEN_NAME)) 212 builder.add(HIDDEN_NAME, attrs.isHidden()); 213 if (builder.match(ATTRIBUTES_NAME)) 214 builder.add(ATTRIBUTES_NAME, attrs.attributes()); 215 return builder.unmodifiableMap(); 216 } 217 218 /** 219 * Update DOS attributes 220 */ 221 private void updateAttributes(int flag, boolean enable) 222 throws IOException 223 { 224 file.checkWrite(); 225 226 // GetFileAttribtues & SetFileAttributes do not follow links so when 227 // following links we need the final target 228 String path = WindowsLinkSupport.getFinalPath(file, followLinks); 229 try { 230 int oldValue = GetFileAttributes(path); 231 int newValue = oldValue; 232 if (enable) { 233 newValue |= flag; 234 } else { 235 newValue &= ~flag; 236 } 237 if (newValue != oldValue) { 238 SetFileAttributes(path, newValue); 239 } 240 } catch (WindowsException x) { 241 // don't reveal target in exception 242 x.rethrowAsIOException(file); 243 } 244 } 245 246 @Override 247 public void setReadOnly(boolean value) throws IOException { 248 updateAttributes(FILE_ATTRIBUTE_READONLY, value); 249 } 250 251 @Override 252 public void setHidden(boolean value) throws IOException { 253 updateAttributes(FILE_ATTRIBUTE_HIDDEN, value); 254 } 255 256 @Override 257 public void setArchive(boolean value) throws IOException { 258 updateAttributes(FILE_ATTRIBUTE_ARCHIVE, value); 259 } 260 261 @Override 262 public void setSystem(boolean value) throws IOException { 263 updateAttributes(FILE_ATTRIBUTE_SYSTEM, value); 264 } 265 266 // package-private 267 // Copy given attributes to the file. 268 void setAttributes(WindowsFileAttributes attrs) 269 throws IOException 270 { 271 // copy DOS attributes to target 272 int flags = 0; 273 if (attrs.isReadOnly()) flags |= FILE_ATTRIBUTE_READONLY; 274 if (attrs.isHidden()) flags |= FILE_ATTRIBUTE_HIDDEN; 275 if (attrs.isArchive()) flags |= FILE_ATTRIBUTE_ARCHIVE; 276 if (attrs.isSystem()) flags |= FILE_ATTRIBUTE_SYSTEM; 277 updateAttributes(flags, true); 278 279 // copy file times to target - must be done after updating FAT attributes 280 // as otherwise the last modified time may be wrong. 281 setFileTimes( 282 WindowsFileAttributes.toWindowsTime(attrs.creationTime()), 283 WindowsFileAttributes.toWindowsTime(attrs.lastModifiedTime()), 284 WindowsFileAttributes.toWindowsTime(attrs.lastAccessTime())); 285 } 286 } 287 288 static Basic createBasicView(WindowsPath file, boolean followLinks) { 289 return new Basic(file, followLinks); 290 } 291 292 static Dos createDosView(WindowsPath file, boolean followLinks) { 293 return new Dos(file, followLinks); 294 } 295 }