| OLD | NEW | 
|---|
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. | 
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be | 
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. | 
| 4 | 4 | 
| 5 #include "components/filesystem/util.h" | 5 #include "components/filesystem/util.h" | 
| 6 | 6 | 
| 7 #include <errno.h> | 7 #include <errno.h> | 
| 8 #include <fcntl.h> | 8 #include <fcntl.h> | 
| 9 #include <sys/stat.h> | 9 #include <sys/stat.h> | 
| 10 #include <time.h> | 10 #include <time.h> | 
| 11 | 11 | 
| 12 #include <limits> | 12 #include <limits> | 
| 13 | 13 | 
| 14 #include "base/logging.h" | 14 #include "base/logging.h" | 
| 15 #include "base/strings/string_util.h" | 15 #include "base/strings/string_util.h" | 
| 16 #include "mojo/public/cpp/bindings/string.h" | 16 #include "mojo/public/cpp/bindings/string.h" | 
| 17 | 17 | 
|  | 18 // module filesystem has various constants which must line up with enum values | 
|  | 19 // in base::File::Flags. | 
|  | 20 static_assert(filesystem::kFlagOpen == | 
|  | 21                   static_cast<uint32>(base::File::FLAG_OPEN), | 
|  | 22               ""); | 
|  | 23 static_assert(filesystem::kFlagCreate == | 
|  | 24                   static_cast<uint32>(base::File::FLAG_CREATE), | 
|  | 25               ""); | 
|  | 26 static_assert(filesystem::kFlagOpenAlways == | 
|  | 27                   static_cast<uint32>(base::File::FLAG_OPEN_ALWAYS), | 
|  | 28               ""); | 
|  | 29 static_assert(filesystem::kCreateAlways == | 
|  | 30                   static_cast<uint32>(base::File::FLAG_CREATE_ALWAYS), | 
|  | 31               ""); | 
|  | 32 static_assert(filesystem::kFlagOpenTruncated == | 
|  | 33                   static_cast<uint32>(base::File::FLAG_OPEN_TRUNCATED), | 
|  | 34               ""); | 
|  | 35 static_assert(filesystem::kFlagRead == | 
|  | 36                   static_cast<uint32>(base::File::FLAG_READ), | 
|  | 37               ""); | 
|  | 38 static_assert(filesystem::kFlagWrite == | 
|  | 39                   static_cast<uint32>(base::File::FLAG_WRITE), | 
|  | 40               ""); | 
|  | 41 static_assert(filesystem::kFlagAppend == | 
|  | 42                   static_cast<uint32>(base::File::FLAG_APPEND), | 
|  | 43               ""); | 
|  | 44 | 
|  | 45 // filesystem.Error in types.mojom must be the same as base::File::Error. | 
|  | 46 static_assert(static_cast<int>(filesystem::ERROR_OK) == | 
|  | 47                   static_cast<int>(base::File::FILE_OK), | 
|  | 48               ""); | 
|  | 49 static_assert(static_cast<int>(filesystem::ERROR_FAILED) == | 
|  | 50                   static_cast<int>(base::File::FILE_ERROR_FAILED), | 
|  | 51               ""); | 
|  | 52 static_assert(static_cast<int>(filesystem::ERROR_IN_USE) == | 
|  | 53                   static_cast<int>(base::File::FILE_ERROR_IN_USE), | 
|  | 54               ""); | 
|  | 55 static_assert(static_cast<int>(filesystem::ERROR_EXISTS) == | 
|  | 56                   static_cast<int>(base::File::FILE_ERROR_EXISTS), | 
|  | 57               ""); | 
|  | 58 static_assert(static_cast<int>(filesystem::ERROR_NOT_FOUND) == | 
|  | 59                   static_cast<int>(base::File::FILE_ERROR_NOT_FOUND), | 
|  | 60               ""); | 
|  | 61 static_assert(static_cast<int>(filesystem::ERROR_ACCESS_DENIED) == | 
|  | 62                   static_cast<int>(base::File::FILE_ERROR_ACCESS_DENIED), | 
|  | 63               ""); | 
|  | 64 static_assert(static_cast<int>(filesystem::ERROR_TOO_MANY_OPENED) == | 
|  | 65                   static_cast<int>(base::File::FILE_ERROR_TOO_MANY_OPENED), | 
|  | 66               ""); | 
|  | 67 static_assert(static_cast<int>(filesystem::ERROR_NO_MEMORY) == | 
|  | 68                   static_cast<int>(base::File::FILE_ERROR_NO_MEMORY), | 
|  | 69               ""); | 
|  | 70 static_assert(static_cast<int>(filesystem::ERROR_NO_SPACE) == | 
|  | 71                   static_cast<int>(base::File::FILE_ERROR_NO_SPACE), | 
|  | 72               ""); | 
|  | 73 static_assert(static_cast<int>(filesystem::ERROR_NOT_A_DIRECTORY) == | 
|  | 74                   static_cast<int>(base::File::FILE_ERROR_NOT_A_DIRECTORY), | 
|  | 75               ""); | 
|  | 76 static_assert(static_cast<int>(filesystem::ERROR_INVALID_OPERATION) == | 
|  | 77                   static_cast<int>(base::File::FILE_ERROR_INVALID_OPERATION), | 
|  | 78               ""); | 
|  | 79 static_assert(static_cast<int>(filesystem::ERROR_SECURITY) == | 
|  | 80                   static_cast<int>(base::File::FILE_ERROR_SECURITY), | 
|  | 81               ""); | 
|  | 82 static_assert(static_cast<int>(filesystem::ERROR_ABORT) == | 
|  | 83                   static_cast<int>(base::File::FILE_ERROR_ABORT), | 
|  | 84               ""); | 
|  | 85 static_assert(static_cast<int>(filesystem::ERROR_NOT_A_FILE) == | 
|  | 86                   static_cast<int>(base::File::FILE_ERROR_NOT_A_FILE), | 
|  | 87               ""); | 
|  | 88 static_assert(static_cast<int>(filesystem::ERROR_NOT_EMPTY) == | 
|  | 89                   static_cast<int>(base::File::FILE_ERROR_NOT_EMPTY), | 
|  | 90               ""); | 
|  | 91 static_assert(static_cast<int>(filesystem::ERROR_INVALID_URL) == | 
|  | 92                   static_cast<int>(base::File::FILE_ERROR_INVALID_URL), | 
|  | 93               ""); | 
|  | 94 static_assert(static_cast<int>(filesystem::ERROR_IO) == | 
|  | 95                   static_cast<int>(base::File::FILE_ERROR_IO), | 
|  | 96               ""); | 
|  | 97 | 
|  | 98 // filesystem.Whence in types.mojom must be the same as base::File::Whence. | 
|  | 99 static_assert(static_cast<int>(filesystem::WHENCE_FROM_BEGIN) == | 
|  | 100                   static_cast<int>(base::File::FROM_BEGIN), | 
|  | 101               ""); | 
|  | 102 static_assert(static_cast<int>(filesystem::WHENCE_FROM_CURRENT) == | 
|  | 103                   static_cast<int>(base::File::FROM_CURRENT), | 
|  | 104               ""); | 
|  | 105 static_assert(static_cast<int>(filesystem::WHENCE_FROM_END) == | 
|  | 106                   static_cast<int>(base::File::FROM_END), | 
|  | 107               ""); | 
|  | 108 | 
| 18 namespace filesystem { | 109 namespace filesystem { | 
| 19 | 110 | 
| 20 Error IsPathValid(const mojo::String& path) { |  | 
| 21   DCHECK(!path.is_null()); |  | 
| 22   if (!base::IsStringUTF8(path.get())) |  | 
| 23     return ERROR_INVALID_ARGUMENT; |  | 
| 24   if (path.size() > 0 && path[0] == '/') |  | 
| 25     return ERROR_PERMISSION_DENIED; |  | 
| 26   return ERROR_OK; |  | 
| 27 } |  | 
| 28 |  | 
| 29 Error IsWhenceValid(Whence whence) { | 111 Error IsWhenceValid(Whence whence) { | 
| 30   return (whence == WHENCE_FROM_CURRENT || whence == WHENCE_FROM_START || | 112   return (whence == WHENCE_FROM_CURRENT || whence == WHENCE_FROM_BEGIN || | 
| 31           whence == WHENCE_FROM_END) | 113           whence == WHENCE_FROM_END) | 
| 32              ? ERROR_OK | 114              ? ERROR_OK | 
| 33              : ERROR_UNIMPLEMENTED; | 115              : ERROR_INVALID_OPERATION; | 
| 34 } | 116 } | 
| 35 | 117 | 
| 36 Error IsOffsetValid(int64_t offset) { | 118 Error IsOffsetValid(int64_t offset) { | 
| 37   return (offset >= std::numeric_limits<off_t>::min() && | 119   return (offset >= std::numeric_limits<off_t>::min() && | 
| 38           offset <= std::numeric_limits<off_t>::max()) | 120           offset <= std::numeric_limits<off_t>::max()) | 
| 39              ? ERROR_OK | 121              ? ERROR_OK | 
| 40              : ERROR_OUT_OF_RANGE; | 122              : ERROR_INVALID_OPERATION; | 
| 41 } | 123 } | 
| 42 | 124 | 
| 43 Error ErrnoToError(int errno_value) { | 125 Error GetError(const base::File& file) { | 
| 44   // TODO(vtl) | 126   return static_cast<filesystem::Error>(file.error_details()); | 
| 45   return ERROR_UNKNOWN; |  | 
| 46 } | 127 } | 
| 47 | 128 | 
| 48 int WhenceToStandardWhence(Whence whence) { | 129 FileInformationPtr MakeFileInformation(const base::File::Info& info) { | 
| 49   DCHECK_EQ(IsWhenceValid(whence), ERROR_OK); | 130   FileInformationPtr file_info(FileInformation::New()); | 
| 50   switch (whence) { | 131   file_info->type = | 
| 51     case WHENCE_FROM_CURRENT: | 132       info.is_directory ? FILE_TYPE_DIRECTORY : FILE_TYPE_REGULAR_FILE; | 
| 52       return SEEK_CUR; | 133   file_info->size = info.size; | 
| 53     case WHENCE_FROM_START: | 134 | 
| 54       return SEEK_SET; | 135   file_info->atime = info.last_accessed.ToDoubleT(); | 
| 55     case WHENCE_FROM_END: | 136   file_info->mtime = info.last_modified.ToDoubleT(); | 
| 56       return SEEK_END; | 137   file_info->ctime = info.creation_time.ToDoubleT(); | 
| 57   } | 138 | 
| 58   NOTREACHED(); | 139   return file_info.Pass(); | 
| 59   return 0; |  | 
| 60 } | 140 } | 
| 61 | 141 | 
| 62 Error TimespecToStandardTimespec(const Timespec* in, struct timespec* out) { | 142 Error ValidatePath(const mojo::String& raw_path, | 
| 63   if (!in) { | 143                    const base::FilePath& filesystem_base, | 
| 64     out->tv_sec = 0; | 144                    base::FilePath* out) { | 
| 65     out->tv_nsec = UTIME_OMIT; | 145   DCHECK(!raw_path.is_null()); | 
| 66     return ERROR_OK; | 146   if (!base::IsStringUTF8(raw_path.get())) | 
|  | 147     return ERROR_INVALID_OPERATION; | 
|  | 148 | 
|  | 149   // TODO(erg): This isn't really what we want. FilePath::AppendRelativePath() | 
|  | 150   // is closer. We need to deal with entirely hostile apps trying to bust this | 
|  | 151   // function to use a possibly maliciously provided |raw_path| to bust out of | 
|  | 152   // |filesystem_base|. | 
|  | 153   base::FilePath full_path = filesystem_base.Append(raw_path); | 
|  | 154   if (full_path.ReferencesParent()) { | 
|  | 155     // TODO(erg): For now, if it references a parent, we'll consider this bad. | 
|  | 156     return ERROR_ACCESS_DENIED; | 
| 67   } | 157   } | 
| 68 | 158 | 
| 69   static_assert(sizeof(int64_t) >= sizeof(time_t), "whoa, time_t is huge"); | 159   *out = full_path; | 
| 70   if (in->seconds < std::numeric_limits<time_t>::min() || |  | 
| 71       in->seconds > std::numeric_limits<time_t>::max()) |  | 
| 72     return ERROR_OUT_OF_RANGE; |  | 
| 73 |  | 
| 74   if (in->nanoseconds < 0 || in->nanoseconds >= 1000000000) |  | 
| 75     return ERROR_INVALID_ARGUMENT; |  | 
| 76 |  | 
| 77   out->tv_sec = static_cast<time_t>(in->seconds); |  | 
| 78   out->tv_nsec = static_cast<long>(in->nanoseconds); |  | 
| 79   return ERROR_OK; | 160   return ERROR_OK; | 
| 80 } | 161 } | 
| 81 | 162 | 
| 82 Error TimespecOrNowToStandardTimespec(const TimespecOrNow* in, |  | 
| 83                                       struct timespec* out) { |  | 
| 84   if (!in) { |  | 
| 85     out->tv_sec = 0; |  | 
| 86     out->tv_nsec = UTIME_OMIT; |  | 
| 87     return ERROR_OK; |  | 
| 88   } |  | 
| 89 |  | 
| 90   if (in->now) { |  | 
| 91     if (!in->timespec.is_null()) |  | 
| 92       return ERROR_INVALID_ARGUMENT; |  | 
| 93     out->tv_sec = 0; |  | 
| 94     out->tv_nsec = UTIME_NOW; |  | 
| 95     return ERROR_OK; |  | 
| 96   } |  | 
| 97 |  | 
| 98   return TimespecToStandardTimespec(in->timespec.get(), out); |  | 
| 99 } |  | 
| 100 |  | 
| 101 Error ValidateOpenFlags(uint32_t open_flags, bool is_directory) { |  | 
| 102   // Treat unknown flags as "unimplemented". |  | 
| 103   if ((open_flags & |  | 
| 104        ~(kOpenFlagRead | kOpenFlagWrite | kOpenFlagCreate | kOpenFlagExclusive | |  | 
| 105          kOpenFlagAppend | kOpenFlagTruncate))) |  | 
| 106     return ERROR_UNIMPLEMENTED; |  | 
| 107 |  | 
| 108   // At least one of |kOpenFlagRead| or |kOpenFlagWrite| must be set. |  | 
| 109   if (!(open_flags & (kOpenFlagRead | kOpenFlagWrite))) |  | 
| 110     return ERROR_INVALID_ARGUMENT; |  | 
| 111 |  | 
| 112   // |kOpenFlagCreate| requires |kOpenFlagWrite|. |  | 
| 113   if ((open_flags & kOpenFlagCreate) && !(open_flags & kOpenFlagWrite)) |  | 
| 114     return ERROR_INVALID_ARGUMENT; |  | 
| 115 |  | 
| 116   // |kOpenFlagExclusive| requires |kOpenFlagCreate|. |  | 
| 117   if ((open_flags & kOpenFlagExclusive) && !(open_flags & kOpenFlagCreate)) |  | 
| 118     return ERROR_INVALID_ARGUMENT; |  | 
| 119 |  | 
| 120   if (is_directory) { |  | 
| 121     // Check that file-only flags aren't set. |  | 
| 122     if ((open_flags & (kOpenFlagAppend | kOpenFlagTruncate))) |  | 
| 123       return ERROR_INVALID_ARGUMENT; |  | 
| 124     return ERROR_OK; |  | 
| 125   } |  | 
| 126 |  | 
| 127   // File-only flags: |  | 
| 128 |  | 
| 129   // |kOpenFlagAppend| requires |kOpenFlagWrite|. |  | 
| 130   if ((open_flags & kOpenFlagAppend) && !(open_flags & kOpenFlagWrite)) |  | 
| 131     return ERROR_INVALID_ARGUMENT; |  | 
| 132 |  | 
| 133   // |kOpenFlagTruncate| requires |kOpenFlagWrite|. |  | 
| 134   if ((open_flags & kOpenFlagTruncate) && !(open_flags & kOpenFlagWrite)) |  | 
| 135     return ERROR_INVALID_ARGUMENT; |  | 
| 136 |  | 
| 137   return ERROR_OK; |  | 
| 138 } |  | 
| 139 |  | 
| 140 Error ValidateDeleteFlags(uint32_t delete_flags) { |  | 
| 141   // Treat unknown flags as "unimplemented". |  | 
| 142   if ((delete_flags & |  | 
| 143        ~(kDeleteFlagFileOnly | kDeleteFlagDirectoryOnly | |  | 
| 144          kDeleteFlagRecursive))) |  | 
| 145     return ERROR_UNIMPLEMENTED; |  | 
| 146 |  | 
| 147   // Only one of the three currently-defined flags may be set. |  | 
| 148   if ((delete_flags & kDeleteFlagFileOnly) && |  | 
| 149       (delete_flags & (kDeleteFlagDirectoryOnly | kDeleteFlagRecursive))) |  | 
| 150     return ERROR_INVALID_ARGUMENT; |  | 
| 151   if ((delete_flags & kDeleteFlagDirectoryOnly) && |  | 
| 152       (delete_flags & (kDeleteFlagFileOnly | kDeleteFlagRecursive))) |  | 
| 153     return ERROR_INVALID_ARGUMENT; |  | 
| 154   if ((delete_flags & kDeleteFlagRecursive) && |  | 
| 155       (delete_flags & (kDeleteFlagFileOnly | kDeleteFlagDirectoryOnly))) |  | 
| 156     return ERROR_INVALID_ARGUMENT; |  | 
| 157 |  | 
| 158   return ERROR_OK; |  | 
| 159 } |  | 
| 160 |  | 
| 161 }  // namespace filesystem | 163 }  // namespace filesystem | 
| OLD | NEW | 
|---|