Add an async flag to mojo_base.mojo.File

Currently the async flag in base::File isn't serialized when passing
Files between processes. There are assertions and checks on the value
of this flag in several places, so it needs to be preserved during
serialization/deserialization. On Windows we can't check whether an
existing file handle is async or not, so we have to explicitly pass
the flag around.

Bug: 845612
Change-Id: I8847ecd9451c13f7419e96db465caa417f4c543d
Reviewed-on: https://chromium-review.googlesource.com/1096480
Commit-Queue: Robbie McElrath <rmcelrath@chromium.org>
Reviewed-by: Matt Menke <mmenke@chromium.org>
Reviewed-by: Ken Rockot <rockot@chromium.org>
Reviewed-by: Daniel Cheng <dcheng@chromium.org>
Cr-Original-Commit-Position: refs/heads/master@{#568662}
Cr-Mirrored-From: https://chromium.googlesource.com/chromium/src
Cr-Mirrored-Commit: d798079d315b6acedc797101a6c808ff826d32a0
diff --git a/files/file.cc b/files/file.cc
index 1a4ee37..e8934b1 100644
--- a/files/file.cc
+++ b/files/file.cc
@@ -36,11 +36,13 @@
 }
 #endif
 
-File::File(PlatformFile platform_file)
+File::File(PlatformFile platform_file) : File(platform_file, false) {}
+
+File::File(PlatformFile platform_file, bool async)
     : file_(platform_file),
       error_details_(FILE_OK),
       created_(false),
-      async_(false) {
+      async_(async) {
 #if defined(OS_POSIX) || defined(OS_FUCHSIA)
   DCHECK_GE(platform_file, -1);
 #endif
@@ -64,15 +66,6 @@
   Close();
 }
 
-// static
-File File::CreateForAsyncHandle(PlatformFile platform_file) {
-  File file(platform_file);
-  // It would be nice if we could validate that |platform_file| was opened with
-  // FILE_FLAG_OVERLAPPED on Windows but this doesn't appear to be possible.
-  file.async_ = true;
-  return file;
-}
-
 File& File::operator=(File&& other) {
   Close();
   SetPlatformFile(other.TakePlatformFile());
diff --git a/files/file.h b/files/file.h
index c3a31d8..ca99b13 100644
--- a/files/file.h
+++ b/files/file.h
@@ -153,9 +153,14 @@
   // |path| contains path traversal ('..') components.
   File(const FilePath& path, uint32_t flags);
 
-  // Takes ownership of |platform_file|.
+  // Takes ownership of |platform_file| and sets async to false.
   explicit File(PlatformFile platform_file);
 
+  // Takes ownership of |platform_file| and sets async to the given value.
+  // This constructor exists because on Windows you can't check if platform_file
+  // is async or not.
+  File(PlatformFile platform_file, bool async);
+
   // Creates an object with a specific error_details code.
   explicit File(Error error_details);
 
@@ -163,9 +168,6 @@
 
   ~File();
 
-  // Takes ownership of |platform_file|.
-  static File CreateForAsyncHandle(PlatformFile platform_file);
-
   File& operator=(File&& other);
 
   // Creates or opens the given file.
diff --git a/files/file_posix.cc b/files/file_posix.cc
index 45cef58..fffec5e 100644
--- a/files/file_posix.cc
+++ b/files/file_posix.cc
@@ -395,10 +395,7 @@
   if (other_fd == -1)
     return File(File::GetLastFileError());
 
-  File other(other_fd);
-  if (async())
-    other.async_ = true;
-  return other;
+  return File(other_fd, async());
 }
 
 // Static.
diff --git a/files/file_unittest.cc b/files/file_unittest.cc
index 65bf62d..8a57322 100644
--- a/files/file_unittest.cc
+++ b/files/file_unittest.cc
@@ -745,4 +745,18 @@
   file.Close();
   ASSERT_TRUE(base::PathExists(file_path));
 }
+
+// Check that we handle the async bit being set incorrectly in a sane way.
+TEST(FileTest, UseSyncApiWithAsyncFile) {
+  base::ScopedTempDir temp_dir;
+  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+  FilePath file_path = temp_dir.GetPath().AppendASCII("file");
+
+  File file(file_path, base::File::FLAG_CREATE | base::File::FLAG_WRITE |
+                           base::File::FLAG_ASYNC);
+  File lying_file(file.TakePlatformFile(), false /* async */);
+  ASSERT_TRUE(lying_file.IsValid());
+
+  ASSERT_EQ(lying_file.WriteAtCurrentPos("12345", 5), -1);
+}
 #endif  // defined(OS_WIN)
diff --git a/files/file_win.cc b/files/file_win.cc
index d7bffc3..82cd7e8 100644
--- a/files/file_win.cc
+++ b/files/file_win.cc
@@ -269,10 +269,7 @@
     return File(GetLastFileError());
   }
 
-  File other(other_handle);
-  if (async())
-    other.async_ = true;
-  return other;
+  return File(other_handle, async());
 }
 
 bool File::DeleteOnClose(bool delete_on_close) {