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 "DOMFileSystemSync.h"
33
34#if ENABLE(FILE_SYSTEM)
35
36#include "AsyncFileSystem.h"
37#include "AsyncFileWriter.h"
38#include "DOMFilePath.h"
39#include "DirectoryEntrySync.h"
40#include "ErrorCallback.h"
41#include "File.h"
42#include "FileEntrySync.h"
43#include "FileError.h"
44#include "FileException.h"
45#include "FileMetadata.h"
46#include "FileSystemCallbacks.h"
47#include "FileWriterBaseCallback.h"
48#include "FileWriterSync.h"
49
50namespace WebCore {
51
52class FileWriterBase;
53
54PassRefPtr<DOMFileSystemSync> DOMFileSystemSync::create(DOMFileSystemBase* fileSystem)
55{
56    return adoptRef(new DOMFileSystemSync(fileSystem->m_context, fileSystem->m_name, fileSystem->m_asyncFileSystem.release()));
57}
58
59DOMFileSystemSync::DOMFileSystemSync(ScriptExecutionContext* context, const String& name, PassOwnPtr<AsyncFileSystem> asyncFileSystem)
60    : DOMFileSystemBase(context, name, asyncFileSystem)
61{
62}
63
64DOMFileSystemSync::~DOMFileSystemSync()
65{
66}
67
68PassRefPtr<DirectoryEntrySync> DOMFileSystemSync::root()
69{
70    return DirectoryEntrySync::create(this, DOMFilePath::root);
71}
72
73namespace {
74
75class GetPathHelper : public AsyncFileSystemCallbacks {
76public:
77    class GetPathResult : public RefCounted<GetPathResult> {
78      public:
79        static PassRefPtr<GetPathResult> create()
80        {
81            return adoptRef(new GetPathResult());
82        }
83
84        bool m_failed;
85        int m_code;
86        String m_path;
87
88      private:
89        GetPathResult()
90            : m_failed(false)
91            , m_code(0)
92        {
93        }
94
95        ~GetPathResult()
96        {
97        }
98        friend class WTF::RefCounted<GetPathResult>;
99    };
100
101    static PassOwnPtr<GetPathHelper> create(PassRefPtr<GetPathResult> result)
102    {
103        return adoptPtr(new GetPathHelper(result));
104    }
105
106    virtual void didSucceed()
107    {
108        ASSERT_NOT_REACHED();
109    }
110
111    virtual void didOpenFileSystem(const String&, PassOwnPtr<AsyncFileSystem>)
112    {
113        ASSERT_NOT_REACHED();
114    }
115
116    virtual void didReadDirectoryEntry(const String&, bool)
117    {
118        ASSERT_NOT_REACHED();
119    }
120
121    virtual void didReadDirectoryEntries(bool)
122    {
123        ASSERT_NOT_REACHED();
124    }
125
126    virtual void didCreateFileWriter(PassOwnPtr<AsyncFileWriter>, long long)
127    {
128        ASSERT_NOT_REACHED();
129    }
130
131    virtual void didFail(int code)
132    {
133        m_result->m_failed = true;
134        m_result->m_code = code;
135    }
136
137    virtual ~GetPathHelper()
138    {
139    }
140
141    void didReadMetadata(const FileMetadata& metadata)
142    {
143        m_result->m_path = metadata.platformPath;
144    }
145private:
146    GetPathHelper(PassRefPtr<GetPathResult> result)
147        : m_result(result)
148    {
149    }
150
151    RefPtr<GetPathResult> m_result;
152};
153
154} // namespace
155
156PassRefPtr<File> DOMFileSystemSync::createFile(const FileEntrySync* fileEntry, ExceptionCode& ec)
157{
158    ec = 0;
159    String platformPath = m_asyncFileSystem->virtualToPlatformPath(fileEntry->fullPath());
160    RefPtr<GetPathHelper::GetPathResult> result(GetPathHelper::GetPathResult::create());
161    m_asyncFileSystem->readMetadata(platformPath, GetPathHelper::create(result));
162    if (!m_asyncFileSystem->waitForOperationToComplete()) {
163        ec = FileException::ABORT_ERR;
164        return 0;
165    }
166    if (result->m_failed) {
167        ec = result->m_code;
168        return 0;
169    }
170    if (!result->m_path.isEmpty())
171        platformPath = result->m_path;
172    return File::create(platformPath);
173}
174
175namespace {
176
177class ReceiveFileWriterCallback : public FileWriterBaseCallback {
178public:
179    static PassRefPtr<ReceiveFileWriterCallback> create()
180    {
181        return adoptRef(new ReceiveFileWriterCallback());
182    }
183
184    bool handleEvent(FileWriterBase* fileWriterBase)
185    {
186#ifndef NDEBUG
187        m_fileWriterBase = fileWriterBase;
188#else
189        ASSERT_UNUSED(fileWriterBase, fileWriterBase);
190#endif
191        return true;
192    }
193
194#ifndef NDEBUG
195    FileWriterBase* fileWriterBase()
196    {
197        return m_fileWriterBase;
198    }
199#endif
200
201private:
202    ReceiveFileWriterCallback()
203#ifndef NDEBUG
204        : m_fileWriterBase(0)
205#endif
206    {
207    }
208
209#ifndef NDEBUG
210    FileWriterBase* m_fileWriterBase;
211#endif
212};
213
214class LocalErrorCallback : public ErrorCallback {
215public:
216    static PassRefPtr<LocalErrorCallback> create()
217    {
218        return adoptRef(new LocalErrorCallback());
219    }
220
221    bool handleEvent(FileError* error)
222    {
223        m_error = error;
224        return true;
225    }
226
227    FileError* error()
228    {
229        return m_error.get();
230    }
231
232private:
233    LocalErrorCallback()
234    {
235    }
236    RefPtr<FileError> m_error;
237};
238
239}
240
241PassRefPtr<FileWriterSync> DOMFileSystemSync::createWriter(const FileEntrySync* fileEntry, ExceptionCode& ec)
242{
243    ASSERT(fileEntry);
244    ec = 0;
245
246    String platformPath = m_asyncFileSystem->virtualToPlatformPath(fileEntry->fullPath());
247
248    RefPtr<FileWriterSync> fileWriter = FileWriterSync::create();
249    RefPtr<ReceiveFileWriterCallback> successCallback = ReceiveFileWriterCallback::create();
250    RefPtr<LocalErrorCallback> errorCallback = LocalErrorCallback::create();
251
252    OwnPtr<FileWriterBaseCallbacks> callbacks = FileWriterBaseCallbacks::create(fileWriter, successCallback, errorCallback);
253    m_asyncFileSystem->createWriter(fileWriter.get(), platformPath, callbacks.release());
254    if (!m_asyncFileSystem->waitForOperationToComplete()) {
255        ec = FileException::ABORT_ERR;
256        return 0;
257    }
258    if (errorCallback->error()) {
259        ASSERT(!successCallback->fileWriterBase());
260        ec = FileException::ErrorCodeToExceptionCode(errorCallback->error()->code());
261        return 0;
262    }
263    ASSERT(successCallback->fileWriterBase());
264    ASSERT(static_cast<FileWriterSync*>(successCallback->fileWriterBase()) == fileWriter.get());
265    return fileWriter;
266}
267
268}
269
270#endif // ENABLE(FILE_SYSTEM)
271