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 Dos(WindowsPath file, boolean followLinks) { 161 super(file, followLinks); 162 } 163 164 @Override 165 public String name() { 166 return "dos"; 167 } 168 169 @Override 170 public void setAttribute(String attribute, Object value) 171 throws IOException 172 { 173 if (attribute.equals(READONLY_NAME)) { 174 setReadOnly((Boolean)value); 175 return; 176 } 177 if (attribute.equals(ARCHIVE_NAME)) { 178 setArchive((Boolean)value); 179 return; 180 } 181 if (attribute.equals(SYSTEM_NAME)) { 182 setSystem((Boolean)value); 183 return; 184 } 185 if (attribute.equals(HIDDEN_NAME)) { 186 setHidden((Boolean)value); 187 return; 188 } 189 super.setAttribute(attribute, value); 190 } 191 192 @Override 193 public Map<String,Object> readAttributes(String[] attributes) 194 throws IOException 195 { 196 AttributesBuilder builder = AttributesBuilder.create(attributes); 197 WindowsFileAttributes attrs = readAttributes(); 198 addBasicAttributesToBuilder(attrs, builder); 199 if (builder.match(READONLY_NAME)) 200 builder.add(READONLY_NAME, attrs.isReadOnly()); 201 if (builder.match(ARCHIVE_NAME)) 202 builder.add(ARCHIVE_NAME, attrs.isArchive()); 203 if (builder.match(SYSTEM_NAME)) 204 builder.add(SYSTEM_NAME, attrs.isSystem()); 205 if (builder.match(HIDDEN_NAME)) 206 builder.add(HIDDEN_NAME, attrs.isHidden()); 207 if (builder.match(ATTRIBUTES_NAME)) 208 builder.add(ATTRIBUTES_NAME, attrs.attributes()); 209 return builder.unmodifiableMap(); 210 } 211 212 /** 213 * Update DOS attributes 214 */ 215 private void updateAttributes(int flag, boolean enable) 216 throws IOException 217 { 218 file.checkWrite(); 219 220 // GetFileAttribtues & SetFileAttributes do not follow links so when 221 // following links we need the final target 222 String path = WindowsLinkSupport.getFinalPath(file, followLinks); 223 try { 224 int oldValue = GetFileAttributes(path); 225 int newValue = oldValue; 226 if (enable) { 227 newValue |= flag; 228 } else { 229 newValue &= ~flag; 230 } 231 if (newValue != oldValue) { 232 SetFileAttributes(path, newValue); 233 } 234 } catch (WindowsException x) { 235 // don't reveal target in exception 236 x.rethrowAsIOException(file); 237 } 238 } 239 240 @Override 241 public void setReadOnly(boolean value) throws IOException { 242 updateAttributes(FILE_ATTRIBUTE_READONLY, value); 243 } 244 245 @Override 246 public void setHidden(boolean value) throws IOException { 247 updateAttributes(FILE_ATTRIBUTE_HIDDEN, value); 248 } 249 250 @Override 251 public void setArchive(boolean value) throws IOException { 252 updateAttributes(FILE_ATTRIBUTE_ARCHIVE, value); 253 } 254 255 @Override 256 public void setSystem(boolean value) throws IOException { 257 updateAttributes(FILE_ATTRIBUTE_SYSTEM, value); 258 } 259 260 // package-private 261 // Copy given attributes to the file. 262 void setAttributes(WindowsFileAttributes attrs) 263 throws IOException 264 { 265 // copy DOS attributes to target 266 int flags = 0; 267 if (attrs.isReadOnly()) flags |= FILE_ATTRIBUTE_READONLY; 268 if (attrs.isHidden()) flags |= FILE_ATTRIBUTE_HIDDEN; 269 if (attrs.isArchive()) flags |= FILE_ATTRIBUTE_ARCHIVE; 270 if (attrs.isSystem()) flags |= FILE_ATTRIBUTE_SYSTEM; 271 updateAttributes(flags, true); 272 273 // copy file times to target - must be done after updating FAT attributes 274 // as otherwise the last modified time may be wrong. 275 setFileTimes( 276 WindowsFileAttributes.toWindowsTime(attrs.creationTime()), 277 WindowsFileAttributes.toWindowsTime(attrs.lastModifiedTime()), 278 WindowsFileAttributes.toWindowsTime(attrs.lastAccessTime())); 279 } 280 } 281 282 static Basic createBasicView(WindowsPath file, boolean followLinks) { 283 return new Basic(file, followLinks); 284 } 285 286 static Dos createDosView(WindowsPath file, boolean followLinks) { 287 return new Dos(file, followLinks); 288 } 289 }