| Index: components/filesystem/util.cc | 
| diff --git a/components/filesystem/util.cc b/components/filesystem/util.cc | 
| index c4797e3e1025ddbd4aee54a79e991b32835ef8bb..e268bc4e057421b584d62a4269df6cbed1efef9c 100644 | 
| --- a/components/filesystem/util.cc | 
| +++ b/components/filesystem/util.cc | 
| @@ -15,146 +15,148 @@ | 
| #include "base/strings/string_util.h" | 
| #include "mojo/public/cpp/bindings/string.h" | 
|  | 
| -namespace filesystem { | 
| +// module filesystem has various constants which must line up with enum values | 
| +// in base::File::Flags. | 
| +static_assert(filesystem::kFlagOpen == | 
| +                  static_cast<uint32>(base::File::FLAG_OPEN), | 
| +              ""); | 
| +static_assert(filesystem::kFlagCreate == | 
| +                  static_cast<uint32>(base::File::FLAG_CREATE), | 
| +              ""); | 
| +static_assert(filesystem::kFlagOpenAlways == | 
| +                  static_cast<uint32>(base::File::FLAG_OPEN_ALWAYS), | 
| +              ""); | 
| +static_assert(filesystem::kCreateAlways == | 
| +                  static_cast<uint32>(base::File::FLAG_CREATE_ALWAYS), | 
| +              ""); | 
| +static_assert(filesystem::kFlagOpenTruncated == | 
| +                  static_cast<uint32>(base::File::FLAG_OPEN_TRUNCATED), | 
| +              ""); | 
| +static_assert(filesystem::kFlagRead == | 
| +                  static_cast<uint32>(base::File::FLAG_READ), | 
| +              ""); | 
| +static_assert(filesystem::kFlagWrite == | 
| +                  static_cast<uint32>(base::File::FLAG_WRITE), | 
| +              ""); | 
| +static_assert(filesystem::kFlagAppend == | 
| +                  static_cast<uint32>(base::File::FLAG_APPEND), | 
| +              ""); | 
| + | 
| +// filesystem.Error in types.mojom must be the same as base::File::Error. | 
| +static_assert(static_cast<int>(filesystem::ERROR_OK) == | 
| +                  static_cast<int>(base::File::FILE_OK), | 
| +              ""); | 
| +static_assert(static_cast<int>(filesystem::ERROR_FAILED) == | 
| +                  static_cast<int>(base::File::FILE_ERROR_FAILED), | 
| +              ""); | 
| +static_assert(static_cast<int>(filesystem::ERROR_IN_USE) == | 
| +                  static_cast<int>(base::File::FILE_ERROR_IN_USE), | 
| +              ""); | 
| +static_assert(static_cast<int>(filesystem::ERROR_EXISTS) == | 
| +                  static_cast<int>(base::File::FILE_ERROR_EXISTS), | 
| +              ""); | 
| +static_assert(static_cast<int>(filesystem::ERROR_NOT_FOUND) == | 
| +                  static_cast<int>(base::File::FILE_ERROR_NOT_FOUND), | 
| +              ""); | 
| +static_assert(static_cast<int>(filesystem::ERROR_ACCESS_DENIED) == | 
| +                  static_cast<int>(base::File::FILE_ERROR_ACCESS_DENIED), | 
| +              ""); | 
| +static_assert(static_cast<int>(filesystem::ERROR_TOO_MANY_OPENED) == | 
| +                  static_cast<int>(base::File::FILE_ERROR_TOO_MANY_OPENED), | 
| +              ""); | 
| +static_assert(static_cast<int>(filesystem::ERROR_NO_MEMORY) == | 
| +                  static_cast<int>(base::File::FILE_ERROR_NO_MEMORY), | 
| +              ""); | 
| +static_assert(static_cast<int>(filesystem::ERROR_NO_SPACE) == | 
| +                  static_cast<int>(base::File::FILE_ERROR_NO_SPACE), | 
| +              ""); | 
| +static_assert(static_cast<int>(filesystem::ERROR_NOT_A_DIRECTORY) == | 
| +                  static_cast<int>(base::File::FILE_ERROR_NOT_A_DIRECTORY), | 
| +              ""); | 
| +static_assert(static_cast<int>(filesystem::ERROR_INVALID_OPERATION) == | 
| +                  static_cast<int>(base::File::FILE_ERROR_INVALID_OPERATION), | 
| +              ""); | 
| +static_assert(static_cast<int>(filesystem::ERROR_SECURITY) == | 
| +                  static_cast<int>(base::File::FILE_ERROR_SECURITY), | 
| +              ""); | 
| +static_assert(static_cast<int>(filesystem::ERROR_ABORT) == | 
| +                  static_cast<int>(base::File::FILE_ERROR_ABORT), | 
| +              ""); | 
| +static_assert(static_cast<int>(filesystem::ERROR_NOT_A_FILE) == | 
| +                  static_cast<int>(base::File::FILE_ERROR_NOT_A_FILE), | 
| +              ""); | 
| +static_assert(static_cast<int>(filesystem::ERROR_NOT_EMPTY) == | 
| +                  static_cast<int>(base::File::FILE_ERROR_NOT_EMPTY), | 
| +              ""); | 
| +static_assert(static_cast<int>(filesystem::ERROR_INVALID_URL) == | 
| +                  static_cast<int>(base::File::FILE_ERROR_INVALID_URL), | 
| +              ""); | 
| +static_assert(static_cast<int>(filesystem::ERROR_IO) == | 
| +                  static_cast<int>(base::File::FILE_ERROR_IO), | 
| +              ""); | 
| + | 
| +// filesystem.Whence in types.mojom must be the same as base::File::Whence. | 
| +static_assert(static_cast<int>(filesystem::WHENCE_FROM_BEGIN) == | 
| +                  static_cast<int>(base::File::FROM_BEGIN), | 
| +              ""); | 
| +static_assert(static_cast<int>(filesystem::WHENCE_FROM_CURRENT) == | 
| +                  static_cast<int>(base::File::FROM_CURRENT), | 
| +              ""); | 
| +static_assert(static_cast<int>(filesystem::WHENCE_FROM_END) == | 
| +                  static_cast<int>(base::File::FROM_END), | 
| +              ""); | 
|  | 
| -Error IsPathValid(const mojo::String& path) { | 
| -  DCHECK(!path.is_null()); | 
| -  if (!base::IsStringUTF8(path.get())) | 
| -    return ERROR_INVALID_ARGUMENT; | 
| -  if (path.size() > 0 && path[0] == '/') | 
| -    return ERROR_PERMISSION_DENIED; | 
| -  return ERROR_OK; | 
| -} | 
| +namespace filesystem { | 
|  | 
| Error IsWhenceValid(Whence whence) { | 
| -  return (whence == WHENCE_FROM_CURRENT || whence == WHENCE_FROM_START || | 
| +  return (whence == WHENCE_FROM_CURRENT || whence == WHENCE_FROM_BEGIN || | 
| whence == WHENCE_FROM_END) | 
| ? ERROR_OK | 
| -             : ERROR_UNIMPLEMENTED; | 
| +             : ERROR_INVALID_OPERATION; | 
| } | 
|  | 
| Error IsOffsetValid(int64_t offset) { | 
| return (offset >= std::numeric_limits<off_t>::min() && | 
| offset <= std::numeric_limits<off_t>::max()) | 
| ? ERROR_OK | 
| -             : ERROR_OUT_OF_RANGE; | 
| -} | 
| - | 
| -Error ErrnoToError(int errno_value) { | 
| -  // TODO(vtl) | 
| -  return ERROR_UNKNOWN; | 
| +             : ERROR_INVALID_OPERATION; | 
| } | 
|  | 
| -int WhenceToStandardWhence(Whence whence) { | 
| -  DCHECK_EQ(IsWhenceValid(whence), ERROR_OK); | 
| -  switch (whence) { | 
| -    case WHENCE_FROM_CURRENT: | 
| -      return SEEK_CUR; | 
| -    case WHENCE_FROM_START: | 
| -      return SEEK_SET; | 
| -    case WHENCE_FROM_END: | 
| -      return SEEK_END; | 
| -  } | 
| -  NOTREACHED(); | 
| -  return 0; | 
| +Error GetError(const base::File& file) { | 
| +  return static_cast<filesystem::Error>(file.error_details()); | 
| } | 
|  | 
| -Error TimespecToStandardTimespec(const Timespec* in, struct timespec* out) { | 
| -  if (!in) { | 
| -    out->tv_sec = 0; | 
| -    out->tv_nsec = UTIME_OMIT; | 
| -    return ERROR_OK; | 
| -  } | 
| - | 
| -  static_assert(sizeof(int64_t) >= sizeof(time_t), "whoa, time_t is huge"); | 
| -  if (in->seconds < std::numeric_limits<time_t>::min() || | 
| -      in->seconds > std::numeric_limits<time_t>::max()) | 
| -    return ERROR_OUT_OF_RANGE; | 
| +FileInformationPtr MakeFileInformation(const base::File::Info& info) { | 
| +  FileInformationPtr file_info(FileInformation::New()); | 
| +  file_info->type = | 
| +      info.is_directory ? FILE_TYPE_DIRECTORY : FILE_TYPE_REGULAR_FILE; | 
| +  file_info->size = info.size; | 
|  | 
| -  if (in->nanoseconds < 0 || in->nanoseconds >= 1000000000) | 
| -    return ERROR_INVALID_ARGUMENT; | 
| +  file_info->atime = info.last_accessed.ToDoubleT(); | 
| +  file_info->mtime = info.last_modified.ToDoubleT(); | 
| +  file_info->ctime = info.creation_time.ToDoubleT(); | 
|  | 
| -  out->tv_sec = static_cast<time_t>(in->seconds); | 
| -  out->tv_nsec = static_cast<long>(in->nanoseconds); | 
| -  return ERROR_OK; | 
| +  return file_info.Pass(); | 
| } | 
|  | 
| -Error TimespecOrNowToStandardTimespec(const TimespecOrNow* in, | 
| -                                      struct timespec* out) { | 
| -  if (!in) { | 
| -    out->tv_sec = 0; | 
| -    out->tv_nsec = UTIME_OMIT; | 
| -    return ERROR_OK; | 
| -  } | 
| - | 
| -  if (in->now) { | 
| -    if (!in->timespec.is_null()) | 
| -      return ERROR_INVALID_ARGUMENT; | 
| -    out->tv_sec = 0; | 
| -    out->tv_nsec = UTIME_NOW; | 
| -    return ERROR_OK; | 
| +Error ValidatePath(const mojo::String& raw_path, | 
| +                   const base::FilePath& filesystem_base, | 
| +                   base::FilePath* out) { | 
| +  DCHECK(!raw_path.is_null()); | 
| +  if (!base::IsStringUTF8(raw_path.get())) | 
| +    return ERROR_INVALID_OPERATION; | 
| + | 
| +  // TODO(erg): This isn't really what we want. FilePath::AppendRelativePath() | 
| +  // is closer. We need to deal with entirely hostile apps trying to bust this | 
| +  // function to use a possibly maliciously provided |raw_path| to bust out of | 
| +  // |filesystem_base|. | 
| +  base::FilePath full_path = filesystem_base.Append(raw_path); | 
| +  if (full_path.ReferencesParent()) { | 
| +    // TODO(erg): For now, if it references a parent, we'll consider this bad. | 
| +    return ERROR_ACCESS_DENIED; | 
| } | 
|  | 
| -  return TimespecToStandardTimespec(in->timespec.get(), out); | 
| -} | 
| - | 
| -Error ValidateOpenFlags(uint32_t open_flags, bool is_directory) { | 
| -  // Treat unknown flags as "unimplemented". | 
| -  if ((open_flags & | 
| -       ~(kOpenFlagRead | kOpenFlagWrite | kOpenFlagCreate | kOpenFlagExclusive | | 
| -         kOpenFlagAppend | kOpenFlagTruncate))) | 
| -    return ERROR_UNIMPLEMENTED; | 
| - | 
| -  // At least one of |kOpenFlagRead| or |kOpenFlagWrite| must be set. | 
| -  if (!(open_flags & (kOpenFlagRead | kOpenFlagWrite))) | 
| -    return ERROR_INVALID_ARGUMENT; | 
| - | 
| -  // |kOpenFlagCreate| requires |kOpenFlagWrite|. | 
| -  if ((open_flags & kOpenFlagCreate) && !(open_flags & kOpenFlagWrite)) | 
| -    return ERROR_INVALID_ARGUMENT; | 
| - | 
| -  // |kOpenFlagExclusive| requires |kOpenFlagCreate|. | 
| -  if ((open_flags & kOpenFlagExclusive) && !(open_flags & kOpenFlagCreate)) | 
| -    return ERROR_INVALID_ARGUMENT; | 
| - | 
| -  if (is_directory) { | 
| -    // Check that file-only flags aren't set. | 
| -    if ((open_flags & (kOpenFlagAppend | kOpenFlagTruncate))) | 
| -      return ERROR_INVALID_ARGUMENT; | 
| -    return ERROR_OK; | 
| -  } | 
| - | 
| -  // File-only flags: | 
| - | 
| -  // |kOpenFlagAppend| requires |kOpenFlagWrite|. | 
| -  if ((open_flags & kOpenFlagAppend) && !(open_flags & kOpenFlagWrite)) | 
| -    return ERROR_INVALID_ARGUMENT; | 
| - | 
| -  // |kOpenFlagTruncate| requires |kOpenFlagWrite|. | 
| -  if ((open_flags & kOpenFlagTruncate) && !(open_flags & kOpenFlagWrite)) | 
| -    return ERROR_INVALID_ARGUMENT; | 
| - | 
| -  return ERROR_OK; | 
| -} | 
| - | 
| -Error ValidateDeleteFlags(uint32_t delete_flags) { | 
| -  // Treat unknown flags as "unimplemented". | 
| -  if ((delete_flags & | 
| -       ~(kDeleteFlagFileOnly | kDeleteFlagDirectoryOnly | | 
| -         kDeleteFlagRecursive))) | 
| -    return ERROR_UNIMPLEMENTED; | 
| - | 
| -  // Only one of the three currently-defined flags may be set. | 
| -  if ((delete_flags & kDeleteFlagFileOnly) && | 
| -      (delete_flags & (kDeleteFlagDirectoryOnly | kDeleteFlagRecursive))) | 
| -    return ERROR_INVALID_ARGUMENT; | 
| -  if ((delete_flags & kDeleteFlagDirectoryOnly) && | 
| -      (delete_flags & (kDeleteFlagFileOnly | kDeleteFlagRecursive))) | 
| -    return ERROR_INVALID_ARGUMENT; | 
| -  if ((delete_flags & kDeleteFlagRecursive) && | 
| -      (delete_flags & (kDeleteFlagFileOnly | kDeleteFlagDirectoryOnly))) | 
| -    return ERROR_INVALID_ARGUMENT; | 
| - | 
| +  *out = full_path; | 
| return ERROR_OK; | 
| } | 
|  | 
|  |