Merge pull request #2748 from bobo1on1/32bitmul
[vuplus_xbmc] / xbmc / filesystem / HDFile.cpp
1 /*
2  * XBMC Media Center
3  * Copyright (c) 2002 Frodo
4  * Portions Copyright (c) by the authors of ffmpeg and xvid
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20
21 #include "system.h"
22 #include "HDFile.h"
23 #include "Util.h"
24 #include "URL.h"
25 #include "utils/AliasShortcutUtils.h"
26 #ifdef _LINUX
27 #include "XHandle.h"
28 #endif
29
30 #include <sys/stat.h>
31 #ifdef _LINUX
32 #include <sys/ioctl.h>
33 #else
34 #include <io.h>
35 #include "utils/CharsetConverter.h"
36 #include "utils/URIUtils.h"
37 #endif
38 #include "utils/log.h"
39
40
41 using namespace XFILE;
42
43 //////////////////////////////////////////////////////////////////////
44 // Construction/Destruction
45 //////////////////////////////////////////////////////////////////////
46
47 //*********************************************************************************************
48 CHDFile::CHDFile()
49     : m_hFile(INVALID_HANDLE_VALUE)
50 {}
51
52 //*********************************************************************************************
53 CHDFile::~CHDFile()
54 {
55   if (m_hFile != INVALID_HANDLE_VALUE) Close();
56 }
57 //*********************************************************************************************
58 CStdString CHDFile::GetLocal(const CURL &url)
59 {
60   CStdString path( url.GetFileName() );
61
62   if( url.GetProtocol().Equals("file", false) )
63   {
64     // file://drive[:]/path
65     // file:///drive:/path
66     CStdString host( url.GetHostName() );
67
68     if(host.size() > 0)
69     {
70       if(host.Right(1) == ":")
71         path = host + "/" + path;
72       else
73         path = host + ":/" + path;
74     }
75   }
76
77 #ifndef _LINUX
78   path.Replace('/', '\\');
79 #endif
80
81   if (IsAliasShortcut(path))
82     TranslateAliasShortcut(path);
83
84   return path;
85 }
86
87 //*********************************************************************************************
88 bool CHDFile::Open(const CURL& url)
89 {
90   CStdString strFile = GetLocal(url);
91
92 #ifdef _WIN32
93   CStdStringW strWFile;
94   g_charsetConverter.utf8ToW(strFile, strWFile, false);
95   m_hFile.attach(CreateFileW(strWFile.c_str(), GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL));
96 #else
97   m_hFile.attach(CreateFile(strFile.c_str(), GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL));
98 #endif
99   if (!m_hFile.isValid()) return false;
100
101   m_i64FilePos = 0;
102   m_i64FileLen = 0;
103
104   return true;
105 }
106
107 bool CHDFile::Exists(const CURL& url)
108 {
109   struct __stat64 buffer;
110   CStdString strFile = GetLocal(url);
111
112 #ifdef _WIN32
113   CStdStringW strWFile;
114   URIUtils::RemoveSlashAtEnd(strFile);
115   g_charsetConverter.utf8ToW(strFile, strWFile, false);
116   return (_wstat64(strWFile.c_str(), &buffer)==0);
117 #else
118   return (_stat64(strFile.c_str(), &buffer)==0);
119 #endif
120 }
121
122 int CHDFile::Stat(struct __stat64* buffer)
123 {
124 #ifdef _LINUX
125   return _fstat64((*m_hFile).fd, buffer);
126 #else
127   // Duplicate the handle, as retrieving and closing a matching crt handle closes the crt handle AND the original Windows handle.
128   HANDLE hFileDup;
129   if (0 == DuplicateHandle(GetCurrentProcess(), (HANDLE)m_hFile, GetCurrentProcess(), &hFileDup, 0, FALSE, DUPLICATE_SAME_ACCESS))
130   {
131     CLog::Log(LOGERROR, __FUNCTION__" - DuplicateHandle()");
132     return -1;
133   }
134
135   int fd;
136   fd = _open_osfhandle((intptr_t)((HANDLE)hFileDup), 0);
137   if (fd == -1)
138   {
139     CLog::Log(LOGERROR, "Stat: fd == -1");
140     return -1;
141   }
142   int result = _fstat64(fd, buffer);
143   _close(fd);
144   return result;
145 #endif
146 }
147
148 int CHDFile::Stat(const CURL& url, struct __stat64* buffer)
149 {
150   CStdString strFile = GetLocal(url);
151
152 #ifdef _WIN32
153   CStdStringW strWFile;
154   // win32 can only stat root drives with a slash at the end
155   if(strFile.length() == 2 && strFile[1] ==':')
156     URIUtils::AddSlashAtEnd(strFile);
157   /* _wstat64 calls FindFirstFileEx. According to MSDN, the path should not end in a trailing backslash.
158     Remove it before calling _wstat64 */
159   if (strFile.length() > 3 && URIUtils::HasSlashAtEnd(strFile))
160     URIUtils::RemoveSlashAtEnd(strFile);
161   g_charsetConverter.utf8ToW(strFile, strWFile, false);
162   return _wstat64(strWFile.c_str(), buffer);
163 #else
164   return _stat64(strFile.c_str(), buffer);
165 #endif
166 }
167
168 bool CHDFile::SetHidden(const CURL &url, bool hidden)
169 {
170 #ifdef _WIN32
171   CStdStringW path;
172   g_charsetConverter.utf8ToW(GetLocal(url), path, false);
173   DWORD attributes = hidden ? FILE_ATTRIBUTE_HIDDEN : FILE_ATTRIBUTE_NORMAL;
174   if (SetFileAttributesW(path.c_str(), attributes))
175     return true;
176 #endif
177   return false;
178 }
179
180 //*********************************************************************************************
181 bool CHDFile::OpenForWrite(const CURL& url, bool bOverWrite)
182 {
183   // make sure it's a legal FATX filename (we are writing to the harddisk)
184   CStdString strPath = GetLocal(url);
185
186 #ifdef _WIN32
187   CStdStringW strWPath;
188   g_charsetConverter.utf8ToW(strPath, strWPath, false);
189   m_hFile.attach(CreateFileW(strWPath.c_str(), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, NULL, bOverWrite ? CREATE_ALWAYS : OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL));
190 #else
191   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 #endif
193   if (!m_hFile.isValid())
194     return false;
195
196   m_i64FilePos = 0;
197   Seek(0, SEEK_SET);
198
199   return true;
200 }
201
202 //*********************************************************************************************
203 unsigned int CHDFile::Read(void *lpBuf, int64_t uiBufSize)
204 {
205   if (!m_hFile.isValid()) return 0;
206   DWORD nBytesRead;
207   if ( ReadFile((HANDLE)m_hFile, lpBuf, (DWORD)uiBufSize, &nBytesRead, NULL) )
208   {
209     m_i64FilePos += nBytesRead;
210     return nBytesRead;
211   }
212   return 0;
213 }
214
215 //*********************************************************************************************
216 int CHDFile::Write(const void *lpBuf, int64_t uiBufSize)
217 {
218   if (!m_hFile.isValid())
219     return 0;
220
221   DWORD nBytesWriten;
222   if ( WriteFile((HANDLE)m_hFile, (void*) lpBuf, (DWORD)uiBufSize, &nBytesWriten, NULL) )
223     return nBytesWriten;
224
225   return 0;
226 }
227
228 //*********************************************************************************************
229 void CHDFile::Close()
230 {
231   m_hFile.reset();
232 }
233
234 //*********************************************************************************************
235 int64_t CHDFile::Seek(int64_t iFilePosition, int iWhence)
236 {
237   LARGE_INTEGER lPos, lNewPos;
238   lPos.QuadPart = iFilePosition;
239   int bSuccess;
240
241   switch (iWhence)
242   {
243   case SEEK_SET:
244     bSuccess = SetFilePointerEx((HANDLE)m_hFile, lPos, &lNewPos, FILE_BEGIN);
245     break;
246
247   case SEEK_CUR:
248     bSuccess = SetFilePointerEx((HANDLE)m_hFile, lPos, &lNewPos, FILE_CURRENT);
249     break;
250
251   case SEEK_END:
252     bSuccess = SetFilePointerEx((HANDLE)m_hFile, lPos, &lNewPos, FILE_END);
253     break;
254
255   default:
256     return -1;
257   }
258   if (bSuccess)
259   {
260     m_i64FilePos = lNewPos.QuadPart;
261     return m_i64FilePos;
262   }
263   else
264     return -1;
265 }
266
267 //*********************************************************************************************
268 int64_t CHDFile::GetLength()
269 {
270   if(m_i64FileLen <= m_i64FilePos || m_i64FileLen == 0)
271   {
272     LARGE_INTEGER i64Size;
273     if(GetFileSizeEx((HANDLE)m_hFile, &i64Size))
274       m_i64FileLen = i64Size.QuadPart;
275     else
276       CLog::Log(LOGERROR, "CHDFile::GetLength - GetFileSizeEx failed with error %d", GetLastError());
277   }
278   return m_i64FileLen;
279 }
280
281 //*********************************************************************************************
282 int64_t CHDFile::GetPosition()
283 {
284   return m_i64FilePos;
285 }
286
287 bool CHDFile::Delete(const CURL& url)
288 {
289   CStdString strFile=GetLocal(url);
290
291 #ifdef _WIN32
292   CStdStringW strWFile;
293   g_charsetConverter.utf8ToW(strFile, strWFile, false);
294   return ::DeleteFileW(strWFile.c_str()) ? true : false;
295 #else
296   return ::DeleteFile(strFile.c_str()) ? true : false;
297 #endif
298 }
299
300 bool CHDFile::Rename(const CURL& url, const CURL& urlnew)
301 {
302   CStdString strFile=GetLocal(url);
303   CStdString strNewFile=GetLocal(urlnew);
304
305 #ifdef _WIN32
306   CStdStringW strWFile;
307   CStdStringW strWNewFile;
308   g_charsetConverter.utf8ToW(strFile, strWFile, false);
309   g_charsetConverter.utf8ToW(strNewFile, strWNewFile, false);
310   return ::MoveFileW(strWFile.c_str(), strWNewFile.c_str()) ? true : false;
311 #else
312   return ::MoveFile(strFile.c_str(), strNewFile.c_str()) ? true : false;
313 #endif
314 }
315
316 void CHDFile::Flush()
317 {
318   ::FlushFileBuffers(m_hFile);
319 }
320
321 int CHDFile::IoControl(EIoControl request, void* param)
322 {
323 #ifdef _LINUX
324   if(request == IOCTRL_NATIVE && param)
325   {
326     SNativeIoControl* s = (SNativeIoControl*)param;
327     return ioctl((*m_hFile).fd, s->request, s->param);
328   }
329 #endif
330   return -1;
331 }
332
333 int CHDFile::Truncate(int64_t size)
334 {
335 #ifdef _WIN32
336   // Duplicate the handle, as retrieving and closing a matching crt handle closes the crt handle AND the original Windows handle.
337   HANDLE hFileDup;
338   if (0 == DuplicateHandle(GetCurrentProcess(), (HANDLE)m_hFile, GetCurrentProcess(), &hFileDup, 0, FALSE, DUPLICATE_SAME_ACCESS))
339   {
340     CLog::Log(LOGERROR, __FUNCTION__" - DuplicateHandle()");
341     return -1;
342   }
343
344   int fd;
345   fd = _open_osfhandle((intptr_t)((HANDLE)hFileDup), 0);
346   if (fd == -1)
347   {
348     CLog::Log(LOGERROR, "Stat: fd == -1");
349     return -1;
350   }
351   int result = _chsize_s(fd, (long) size);
352   _close(fd);
353   return result;
354 #else
355   return ftruncate((*m_hFile).fd, (off_t) size);
356 #endif
357   return -1;
358 }