Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 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 "chrome/common/important_file_writer.h" | 5 #include "chrome/common/important_file_writer.h" |
| 6 | 6 |
| 7 #include <stdio.h> | 7 #include <stdio.h> |
| 8 | 8 |
| 9 #include <string> | 9 #include <string> |
| 10 | 10 |
| (...skipping 18 matching lines...) Expand all Loading... | |
| 29 : path_(path), | 29 : path_(path), |
| 30 data_(data) { | 30 data_(data) { |
| 31 } | 31 } |
| 32 | 32 |
| 33 virtual void Run() { | 33 virtual void Run() { |
| 34 // Write the data to a temp file then rename to avoid data loss if we crash | 34 // Write the data to a temp file then rename to avoid data loss if we crash |
| 35 // while writing the file. Ensure that the temp file is on the same volume | 35 // while writing the file. Ensure that the temp file is on the same volume |
| 36 // as target file, so it can be moved in one step, and that the temp file | 36 // as target file, so it can be moved in one step, and that the temp file |
| 37 // is securely created. | 37 // is securely created. |
| 38 FilePath tmp_file_path; | 38 FilePath tmp_file_path; |
| 39 FILE* tmp_file = file_util::CreateAndOpenTemporaryFileInDir( | 39 if (!file_util::CreateTemporaryFileInDir(path_.DirName(), &tmp_file_path)) { |
| 40 path_.DirName(), &tmp_file_path); | |
| 41 if (!tmp_file) { | |
| 42 LogFailure("could not create temporary file"); | 40 LogFailure("could not create temporary file"); |
| 43 return; | 41 return; |
| 44 } | 42 } |
| 45 | 43 |
| 46 size_t bytes_written = fwrite(data_.data(), 1, data_.length(), tmp_file); | 44 int flags = base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_WRITE; |
| 47 if (!file_util::CloseFile(tmp_file)) { | 45 base::PlatformFile tmp_file = |
| 46 base::CreatePlatformFile(tmp_file_path, flags, NULL, NULL); | |
|
Scott Hess - ex-Googler
2011/08/23 00:54:38
I would prefer if you could not introduce a race c
rvargas (doing something else)
2011/08/23 01:41:52
I was writing the code with some posix specific ve
Scott Hess - ex-Googler
2011/08/23 19:23:57
The rename case is a very good point! I won't dig
| |
| 47 if (tmp_file == base::kInvalidPlatformFileValue) { | |
| 48 LogFailure("could not open temporary file"); | |
| 49 return; | |
| 50 } | |
| 51 | |
| 52 CHECK_LE(data_.length(), static_cast<size_t>(kint32max)); | |
| 53 int bytes_written = base::WritePlatformFile( | |
| 54 tmp_file, 0, data_.data(), static_cast<int>(data_.length())); | |
|
Scott Hess - ex-Googler
2011/08/23 19:27:17
BTW ... AFAICT the POSIX version of this function
rvargas (doing something else)
2011/08/23 23:36:58
In that case, line 63 should detect the error and
| |
| 55 base::FlushPlatformFile(tmp_file); // Ignore return value. | |
|
Scott Hess - ex-Googler
2011/08/23 00:54:38
Would it be reasonable to wire up something like f
rvargas (doing something else)
2011/08/23 01:41:52
Not sure. I can make fflush do the right thing on
Scott Hess - ex-Googler
2011/08/23 19:23:57
OK, that's all I wanted to hear - I hate having mu
| |
| 56 | |
| 57 if (!base::ClosePlatformFile(tmp_file)) { | |
| 48 LogFailure("failed to close temporary file"); | 58 LogFailure("failed to close temporary file"); |
| 49 file_util::Delete(tmp_file_path, false); | 59 file_util::Delete(tmp_file_path, false); |
| 50 return; | 60 return; |
| 51 } | 61 } |
| 52 if (bytes_written < data_.length()) { | 62 |
| 63 if (bytes_written < static_cast<int>(data_.length())) { | |
| 53 LogFailure("error writing, bytes_written=" + | 64 LogFailure("error writing, bytes_written=" + |
| 54 base::Uint64ToString(bytes_written)); | 65 base::IntToString(bytes_written)); |
| 55 file_util::Delete(tmp_file_path, false); | 66 file_util::Delete(tmp_file_path, false); |
| 56 return; | 67 return; |
| 57 } | 68 } |
| 58 | 69 |
| 59 if (!file_util::ReplaceFile(tmp_file_path, path_)) { | 70 if (!file_util::ReplaceFile(tmp_file_path, path_)) { |
| 60 LogFailure("could not rename temporary file"); | 71 LogFailure("could not rename temporary file"); |
| 61 file_util::Delete(tmp_file_path, false); | 72 file_util::Delete(tmp_file_path, false); |
| 62 return; | 73 return; |
| 63 } | 74 } |
| 64 } | 75 } |
| (...skipping 30 matching lines...) Expand all Loading... | |
| 95 DCHECK(!HasPendingWrite()); | 106 DCHECK(!HasPendingWrite()); |
| 96 } | 107 } |
| 97 | 108 |
| 98 bool ImportantFileWriter::HasPendingWrite() const { | 109 bool ImportantFileWriter::HasPendingWrite() const { |
| 99 DCHECK(CalledOnValidThread()); | 110 DCHECK(CalledOnValidThread()); |
| 100 return timer_.IsRunning(); | 111 return timer_.IsRunning(); |
| 101 } | 112 } |
| 102 | 113 |
| 103 void ImportantFileWriter::WriteNow(const std::string& data) { | 114 void ImportantFileWriter::WriteNow(const std::string& data) { |
| 104 DCHECK(CalledOnValidThread()); | 115 DCHECK(CalledOnValidThread()); |
| 116 if (data.length() > static_cast<size_t>(kint32max)) { | |
| 117 NOTREACHED(); | |
| 118 return; | |
| 119 } | |
| 105 | 120 |
| 106 if (HasPendingWrite()) | 121 if (HasPendingWrite()) |
| 107 timer_.Stop(); | 122 timer_.Stop(); |
| 108 | 123 |
| 109 if (!file_message_loop_proxy_->PostTask( | 124 if (!file_message_loop_proxy_->PostTask( |
| 110 FROM_HERE, new WriteToDiskTask(path_, data))) { | 125 FROM_HERE, new WriteToDiskTask(path_, data))) { |
| 111 // Posting the task to background message loop is not expected | 126 // Posting the task to background message loop is not expected |
| 112 // to fail, but if it does, avoid losing data and just hit the disk | 127 // to fail, but if it does, avoid losing data and just hit the disk |
| 113 // on the current thread. | 128 // on the current thread. |
| 114 NOTREACHED(); | 129 NOTREACHED(); |
| (...skipping 25 matching lines...) Expand all Loading... | |
| 140 DCHECK(serializer_); | 155 DCHECK(serializer_); |
| 141 std::string data; | 156 std::string data; |
| 142 if (serializer_->SerializeData(&data)) { | 157 if (serializer_->SerializeData(&data)) { |
| 143 WriteNow(data); | 158 WriteNow(data); |
| 144 } else { | 159 } else { |
| 145 LOG(WARNING) << "failed to serialize data to be saved in " | 160 LOG(WARNING) << "failed to serialize data to be saved in " |
| 146 << path_.value(); | 161 << path_.value(); |
| 147 } | 162 } |
| 148 serializer_ = NULL; | 163 serializer_ = NULL; |
| 149 } | 164 } |
| OLD | NEW |