1 /* 2 * Copyright (C) 2010 Google Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions are 6 * met: 7 * 8 * * Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * * Redistributions in binary form must reproduce the above 11 * copyright notice, this list of conditions and the following disclaimer 12 * in the documentation and/or other materials provided with the 13 * distribution. 14 * * Neither the name of Google Inc. nor the names of its 15 * contributors may be used to endorse or promote products derived from 16 * this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31 #include "config.h" 32 #include "DOMFilePath.h" 33 34 #if ENABLE(FILE_SYSTEM) 35 36 #include "RegularExpression.h" 37 #include <wtf/Vector.h> 38 #include <wtf/text/CString.h> 39 40 namespace WebCore { 41 42 const char DOMFilePath::separator = '/'; 43 const char DOMFilePath::root[] = "/"; 44 45 String DOMFilePath::append(const String& base, const String& components) 46 { 47 return ensureDirectoryPath(base) + components; 48 } 49 50 String DOMFilePath::ensureDirectoryPath(const String& path) 51 { 52 if (!DOMFilePath::endsWithSeparator(path)) { 53 String newPath = path; 54 newPath.append(DOMFilePath::separator); 55 return newPath; 56 } 57 return path; 58 } 59 60 String DOMFilePath::getName(const String& path) 61 { 62 int index = path.reverseFind(DOMFilePath::separator); 63 if (index != -1) 64 return path.substring(index + 1); 65 return path; 66 } 67 68 String DOMFilePath::getDirectory(const String& path) 69 { 70 int index = path.reverseFind(DOMFilePath::separator); 71 if (index == 0) 72 return DOMFilePath::root; 73 if (index != -1) 74 return path.substring(0, index); 75 return "."; 76 } 77 78 bool DOMFilePath::isParentOf(const String& parent, const String& mayBeChild) 79 { 80 ASSERT(DOMFilePath::isAbsolute(parent)); 81 ASSERT(DOMFilePath::isAbsolute(mayBeChild)); 82 if (parent == DOMFilePath::root && mayBeChild != DOMFilePath::root) 83 return true; 84 if (parent.length() >= mayBeChild.length() || !mayBeChild.startsWith(parent, false)) 85 return false; 86 if (mayBeChild[parent.length()] != DOMFilePath::separator) 87 return false; 88 return true; 89 } 90 91 String DOMFilePath::removeExtraParentReferences(const String& path) 92 { 93 ASSERT(DOMFilePath::isAbsolute(path)); 94 Vector<String> components; 95 Vector<String> canonicalized; 96 path.split(DOMFilePath::separator, components); 97 for (size_t i = 0; i < components.size(); ++i) { 98 if (components[i] == ".") 99 continue; 100 if (components[i] == "..") { 101 if (canonicalized.size() > 0) 102 canonicalized.removeLast(); 103 continue; 104 } 105 canonicalized.append(components[i]); 106 } 107 if (canonicalized.isEmpty()) 108 return DOMFilePath::root; 109 String result; 110 for (size_t i = 0; i < canonicalized.size(); ++i) { 111 result.append(DOMFilePath::separator); 112 result.append(canonicalized[i]); 113 } 114 return result; 115 } 116 117 // Check the naming restrictions defined in FileSystem API 8.3. 118 // http://dev.w3.org/2009/dap/file-system/file-dir-sys.html#naming-restrictions 119 bool DOMFilePath::isValidPath(const String& path) 120 { 121 if (path.isEmpty() || path == DOMFilePath::root) 122 return true; 123 124 // Chars 0-31 in UTF-8 prepresentation are not allowed. 125 for (size_t i = 0; i < path.length(); ++i) 126 if (path[i] < 32) 127 return false; 128 129 // Unallowed names. 130 DEFINE_STATIC_LOCAL(RegularExpression, unallowedNamesRegExp1, ("(/|^)(CON|PRN|AUX|NUL)([\\./]|$)", TextCaseInsensitive)); 131 DEFINE_STATIC_LOCAL(RegularExpression, unallowedNamesRegExp2, ("(/|^)(COM|LPT)[1-9]([\\./]|$)", TextCaseInsensitive)); 132 133 if (unallowedNamesRegExp1.match(path) >= 0) 134 return false; 135 if (unallowedNamesRegExp2.match(path) >= 0) 136 return false; 137 138 // Names must not end with period or whitespace. 139 DEFINE_STATIC_LOCAL(RegularExpression, endingRegExp, ("[\\.\\s](/|$)", TextCaseInsensitive)); 140 141 if (endingRegExp.match(path) >= 0) 142 return false; 143 144 // Unallowed chars: '\', '<', '>', ':', '?', '*', '"', '|' 145 // (We don't check '/' here as this method takes paths as its argument.) 146 DEFINE_STATIC_LOCAL(RegularExpression, unallowedCharsRegExp, ("[\\\\<>:\\?\\*\"|]", TextCaseInsensitive)); 147 148 if (unallowedCharsRegExp.match(path) >= 0) 149 return false; 150 151 return true; 152 } 153 154 bool DOMFilePath::isValidName(const String& name) 155 { 156 if (name.isEmpty()) 157 return true; 158 // '/' is not allowed in name. 159 if (name.contains('/')) 160 return false; 161 return isValidPath(name); 162 } 163 164 } // namespace WebCore 165 166 #endif // ENABLE(FILE_SYSTEM) 167