2 * Copyright (c) 2002 Frodo
3 * Portions Copyright (c) by the authors of ffmpeg and xvid
4 * Copyright (C) 2002-2013 Team XBMC
7 * This Program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2, or (at your option)
12 * This Program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with XBMC; see the file COPYING. If not, see
19 * <http://www.gnu.org/licenses/>.
27 #include "utils/AliasShortcutUtils.h"
35 #include <sys/ioctl.h>
38 #include "utils/CharsetConverter.h"
39 #include "utils/URIUtils.h"
40 #include "win32/WIN32Util.h"
42 #include "utils/log.h"
46 using namespace XFILE;
48 //////////////////////////////////////////////////////////////////////
49 // Construction/Destruction
50 //////////////////////////////////////////////////////////////////////
52 //*********************************************************************************************
54 : m_hFile(INVALID_HANDLE_VALUE),
58 //*********************************************************************************************
61 if (m_hFile != INVALID_HANDLE_VALUE) Close();
63 //*********************************************************************************************
64 std::string CHDFile::GetLocal(const CURL &url)
66 std::string path(url.GetFileName());
68 if(url.GetProtocol() == "file")
70 // file://drive[:]/path
71 // file:///drive:/path
72 std::string host(url.GetHostName());
76 if(host[host.length()-1] == ':')
77 path = host + "/" + path;
79 path = host + ":/" + path;
83 if (IsAliasShortcut(path))
84 TranslateAliasShortcut(path);
89 //*********************************************************************************************
90 bool CHDFile::Open(const CURL& url)
92 std::string strFile(GetLocal(url));
95 m_hFile.attach(CreateFileW(CWIN32Util::ConvertPathToWin32Form(strFile).c_str(), GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL));
97 m_hFile.attach(CreateFile(strFile.c_str(), GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL));
99 if (!m_hFile.isValid()) return false;
103 m_i64LastDropPos = 0;
108 bool CHDFile::Exists(const CURL& url)
110 std::string strFile(GetLocal(url));
112 #ifdef TARGET_WINDOWS
113 URIUtils::RemoveSlashAtEnd(strFile);
114 DWORD attributes = GetFileAttributesW(CWIN32Util::ConvertPathToWin32Form(strFile).c_str());
115 if(attributes == INVALID_FILE_ATTRIBUTES)
119 struct __stat64 buffer;
120 return (_stat64(strFile.c_str(), &buffer)==0);
124 int CHDFile::Stat(struct __stat64* buffer)
127 return _fstat64((*m_hFile).fd, buffer);
129 // Duplicate the handle, as retrieving and closing a matching crt handle closes the crt handle AND the original Windows handle.
131 if (0 == DuplicateHandle(GetCurrentProcess(), (HANDLE)m_hFile, GetCurrentProcess(), &hFileDup, 0, FALSE, DUPLICATE_SAME_ACCESS))
133 CLog::Log(LOGERROR, __FUNCTION__" - DuplicateHandle()");
138 fd = _open_osfhandle((intptr_t)((HANDLE)hFileDup), 0);
141 CLog::Log(LOGERROR, "Stat: fd == -1");
144 int result = _fstat64(fd, buffer);
150 int CHDFile::Stat(const CURL& url, struct __stat64* buffer)
152 std::string strFile(GetLocal(url));
154 #ifdef TARGET_WINDOWS
155 std::wstring strWFile(CWIN32Util::ConvertPathToWin32Form(strFile));
156 /* _wstat64 can't handle long paths therefore we remove the \\?\ */
157 CWIN32Util::RemoveExtraLongPathPrefix(strWFile);
158 // win32 can only stat root drives with a slash at the end
159 if(strWFile.length() == 2 && strWFile[1] == L':')
160 strWFile.push_back(L'\\');
161 /* _wstat64 calls FindFirstFileEx. According to MSDN, the path should not end in a trailing backslash.
162 Remove it before calling _wstat64 */
163 else if (strWFile.length() > 3 && URIUtils::HasSlashAtEnd(strFile))
165 return _wstat64(strWFile.c_str(), buffer);
167 return _stat64(strFile.c_str(), buffer);
171 bool CHDFile::SetHidden(const CURL &url, bool hidden)
173 #ifdef TARGET_WINDOWS
174 DWORD attributes = hidden ? FILE_ATTRIBUTE_HIDDEN : FILE_ATTRIBUTE_NORMAL;
175 if (SetFileAttributesW(CWIN32Util::ConvertPathToWin32Form(GetLocal(url)).c_str(), attributes))
181 //*********************************************************************************************
182 bool CHDFile::OpenForWrite(const CURL& url, bool bOverWrite)
184 // make sure it's a legal FATX filename (we are writing to the harddisk)
185 std::string strPath(GetLocal(url));
187 #ifdef TARGET_WINDOWS
188 m_hFile.attach(CreateFileW(CWIN32Util::ConvertPathToWin32Form(strPath).c_str(), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, NULL, bOverWrite ? CREATE_ALWAYS : OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL));
190 m_hFile.attach(CreateFile(strPath.c_str(), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, NULL, bOverWrite ? CREATE_ALWAYS : OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL));
192 if (!m_hFile.isValid())
201 //*********************************************************************************************
202 unsigned int CHDFile::Read(void *lpBuf, int64_t uiBufSize)
204 if (!m_hFile.isValid()) return 0;
206 if ( ReadFile((HANDLE)m_hFile, lpBuf, (DWORD)uiBufSize, &nBytesRead, NULL) )
208 m_i64FilePos += nBytesRead;
209 #if defined(HAVE_POSIX_FADVISE)
210 // Drop the cache between where we last seeked and 16 MB behind where
211 // we are now, to make sure the file doesn't displace everything else.
212 // However, we never throw out the first 16 MB of the file, as we might
213 // want the header etc., and we never ask the OS to drop in chunks of
215 int64_t start_drop = std::max<int64_t>(m_i64LastDropPos, 16 << 20);
216 int64_t end_drop = std::max<int64_t>(m_i64FilePos - (16 << 20), 0);
217 if (end_drop - start_drop >= (1 << 20))
219 posix_fadvise((*m_hFile).fd, start_drop, end_drop - start_drop, POSIX_FADV_DONTNEED);
220 m_i64LastDropPos = end_drop;
228 //*********************************************************************************************
229 int CHDFile::Write(const void *lpBuf, int64_t uiBufSize)
231 if (!m_hFile.isValid())
235 if ( WriteFile((HANDLE)m_hFile, (void*) lpBuf, (DWORD)uiBufSize, &nBytesWriten, NULL) )
241 //*********************************************************************************************
242 void CHDFile::Close()
247 //*********************************************************************************************
248 int64_t CHDFile::Seek(int64_t iFilePosition, int iWhence)
250 LARGE_INTEGER lPos, lNewPos;
251 lPos.QuadPart = iFilePosition;
257 bSuccess = SetFilePointerEx((HANDLE)m_hFile, lPos, &lNewPos, FILE_BEGIN);
261 bSuccess = SetFilePointerEx((HANDLE)m_hFile, lPos, &lNewPos, FILE_CURRENT);
265 bSuccess = SetFilePointerEx((HANDLE)m_hFile, lPos, &lNewPos, FILE_END);
273 if (m_i64FilePos != lNewPos.QuadPart)
275 // If we seek, disable the cache drop heuristic until we
276 // have played sequentially for a while again from here.
277 m_i64LastDropPos = lNewPos.QuadPart;
279 m_i64FilePos = lNewPos.QuadPart;
286 //*********************************************************************************************
287 int64_t CHDFile::GetLength()
289 if(m_i64FileLen <= m_i64FilePos || m_i64FileLen == 0)
291 LARGE_INTEGER i64Size;
292 if(GetFileSizeEx((HANDLE)m_hFile, &i64Size))
293 m_i64FileLen = i64Size.QuadPart;
295 CLog::Log(LOGERROR, "CHDFile::GetLength - GetFileSizeEx failed with error %d", GetLastError());
300 //*********************************************************************************************
301 int64_t CHDFile::GetPosition()
306 bool CHDFile::Delete(const CURL& url)
308 std::string strFile(GetLocal(url));
310 #ifdef TARGET_WINDOWS
311 return ::DeleteFileW(CWIN32Util::ConvertPathToWin32Form(strFile).c_str()) ? true : false;
313 return ::DeleteFile(strFile.c_str()) ? true : false;
317 bool CHDFile::Rename(const CURL& url, const CURL& urlnew)
319 std::string strFile(GetLocal(url));
320 std::string strNewFile(GetLocal(urlnew));
322 #ifdef TARGET_WINDOWS
323 return ::MoveFileW(CWIN32Util::ConvertPathToWin32Form(strFile).c_str(), CWIN32Util::ConvertPathToWin32Form(strNewFile).c_str()) ? true : false;
325 return ::MoveFile(strFile.c_str(), strNewFile.c_str()) ? true : false;
329 void CHDFile::Flush()
331 ::FlushFileBuffers(m_hFile);
334 int CHDFile::IoControl(EIoControl request, void* param)
337 if(request == IOCTRL_NATIVE && param)
339 SNativeIoControl* s = (SNativeIoControl*)param;
340 return ioctl((*m_hFile).fd, s->request, s->param);
346 int CHDFile::Truncate(int64_t size)
348 #ifdef TARGET_WINDOWS
349 // Duplicate the handle, as retrieving and closing a matching crt handle closes the crt handle AND the original Windows handle.
351 if (0 == DuplicateHandle(GetCurrentProcess(), (HANDLE)m_hFile, GetCurrentProcess(), &hFileDup, 0, FALSE, DUPLICATE_SAME_ACCESS))
353 CLog::Log(LOGERROR, __FUNCTION__" - DuplicateHandle()");
358 fd = _open_osfhandle((intptr_t)((HANDLE)hFileDup), 0);
361 CLog::Log(LOGERROR, "Stat: fd == -1");
364 int result = _chsize_s(fd, (long) size);
368 return ftruncate((*m_hFile).fd, (off_t) size);