1/*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <string.h>
18#include <stdio.h>
19#include <fcntl.h>
20#include <errno.h>
21#include <unistd.h>
22#include <stdlib.h>
23#include <dirent.h>
24#include <unistd.h>
25#include <sys/stat.h>
26#include <sys/vfs.h>
27#include <sys/mman.h>
28#include "xpl_Memory.h"
29#include "xpl_File.h"
30#include "xpl_Logger.h"
31#include "dmvector.h"
32
33class DMDirHandler
34{
35public :
36  DMDirHandler()
37  {
38    m_nIndex = 0;
39    m_nDirLen = 0;
40    m_pDir = XPL_NULL;
41
42  }
43 ~DMDirHandler()
44  {
45    if (m_pDir)
46      closedir(m_pDir);
47  }
48
49  void* operator new(size_t dwSize)
50  {
51      return (xplAllocMem(dwSize));
52  }
53
54  void operator delete(void *pvBuf)
55  {
56      xplFreeMem(pvBuf);
57  }
58
59  DMString m_szDirectory;
60  DMString m_szExtension;
61  INT32 m_nIndex;
62  INT32 m_nDirLen;
63  DIR *m_pDir;
64};
65
66
67#ifdef __cplusplus
68extern "C" {
69#endif
70
71
72XPL_FS_HANDLE_T XPL_FS_Open(CPCHAR file_uri,
73                            const XPL_FS_OPEN_MODE_T open_mode,
74                            XPL_FS_RET_STATUS_T * result)
75{
76    int flags = 0;
77    XPL_FS_HANDLE_T nFileHandle;
78
79    if ( result )
80         *result = XPL_FS_RET_SUCCESS;
81
82    switch ( open_mode) {
83    case XPL_FS_FILE_READ:
84      flags = O_RDONLY; /* read-only at current position */
85      break;
86
87    case XPL_FS_FILE_WRITE:
88      flags = O_WRONLY | O_TRUNC | O_CREAT;  /* write-only truncate file */
89      break;
90
91    case XPL_FS_FILE_RDWR:
92      flags = O_RDWR| O_CREAT;  /* read and write at current position */
93      break;
94
95    case XPL_FS_FILE_APPEND:
96      flags = O_WRONLY | O_APPEND | O_CREAT; /* read and write at current position */
97      break;
98    }
99
100    nFileHandle = (XPL_FS_HANDLE_T)open(file_uri, flags, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
101    // XPL_LOG_DM_XPL_Debug(("DMFileHandler::open: opening file %s with mode flag %d, errno is %d, handle = %d\n",file_uri,(int)open_mode, errno, nFileHandle));
102    if ( result && nFileHandle == -1 )
103    {
104      if (errno == EPERM) {   // permission failure
105        *result = XPL_FS_RET_PERM_FAIL;
106      }
107      else {
108        *result = XPL_FS_RET_FAIL;
109      }
110      XPL_LOG_DM_XPL_Error(("DMFileHandler::open: can't open file %s with mode flag %d errno is %d\n",file_uri,(int)open_mode,errno));
111    }
112
113    if ( nFileHandle > 0 && open_mode != XPL_FS_FILE_READ )
114    {
115      chmod(file_uri,S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
116    }
117    return nFileHandle;
118
119}
120
121
122XPL_FS_RET_STATUS_T XPL_FS_Close(XPL_FS_HANDLE_T file_handle)
123{
124    int result =  close((int)file_handle);
125    if ( result < 0 )
126        return XPL_FS_RET_FAIL;
127    else
128        return XPL_FS_RET_SUCCESS;
129}
130
131
132XPL_FS_COUNT_T XPL_FS_Read(XPL_FS_HANDLE_T file_handle,
133                           void* buffer,
134                           const XPL_FS_COUNT_T count,
135                           XPL_FS_RET_STATUS_T * result)
136{
137    if ( result )
138           *result = XPL_FS_RET_SUCCESS;
139    XPL_FS_COUNT_T nRead = (XPL_FS_COUNT_T)read((int)file_handle,buffer,(int)count);
140    if ( result && nRead == -1 )
141           *result = XPL_FS_RET_FAIL;
142    return nRead;
143}
144
145
146XPL_FS_COUNT_T XPL_FS_Write(XPL_FS_HANDLE_T file_handle,
147                            void* buffer,
148                            const XPL_FS_COUNT_T count,
149                            XPL_FS_RET_STATUS_T * result)
150{
151    if ( result )
152          *result = XPL_FS_RET_SUCCESS;
153
154    XPL_FS_COUNT_T nWrite = (XPL_FS_COUNT_T)write((int)file_handle,buffer,(int)count);
155    if ( result && nWrite == -1 ) {
156          XPL_LOG_DM_XPL_Error(("XPL_FS_Write: file_handle %d, nWrite = %d errno is %d\n",file_handle, nWrite, errno));
157          *result = XPL_FS_RET_FAIL;
158    }
159    return nWrite;
160}
161
162
163XPL_FS_SEEK_OFFSET_T XPL_FS_Seek(XPL_FS_HANDLE_T file_handle,
164                                 XPL_FS_SEEK_OFFSET_T offset,
165                                 XPL_FS_SEEK_MODE_T whence,
166                                 XPL_FS_RET_STATUS_T * result)
167{
168    int whence_posix;
169    XPL_FS_SEEK_OFFSET_T result_offset;
170
171    if ( result )
172        *result = XPL_FS_RET_SUCCESS;
173    switch(whence)
174    {
175        case XPL_FS_SEEK_SET:
176              whence_posix = SEEK_SET;
177              break;
178        case XPL_FS_SEEK_CUR:
179              whence_posix = SEEK_CUR;
180              break;
181        case XPL_FS_SEEK_END:
182              whence_posix = SEEK_END;
183              break;
184     }
185     result_offset = lseek(file_handle,offset,whence_posix);
186     if ( result && result_offset == -1)
187         *result = XPL_FS_RET_FAIL;
188     return result_offset;
189
190}
191
192
193XPL_FS_RET_STATUS_T XPL_FS_Remove(CPCHAR path)
194{
195    int result = remove(path);
196    if ( result < 0 )
197        return XPL_FS_RET_FAIL;
198    else
199        return XPL_FS_RET_SUCCESS;
200}
201
202XPL_FS_RET_STATUS_T XPL_FS_Rename(CPCHAR old_name, CPCHAR new_name)
203{
204    int result = rename(old_name, new_name);
205
206    // XPL_LOG_DM_XPL_Debug(("XPL_FS_Rename: old name %s  new name %s result = %d, errno is %d%d\n",old_name,new_name, errno, result));
207
208    if ( result < 0 ) {
209    	XPL_LOG_DM_XPL_Error(("XPL_FS_Rename error: old name %s  new name %s result = %d, errno is %d\n",old_name,new_name, errno, result));
210        return XPL_FS_RET_FAIL;
211    }
212    else
213        return XPL_FS_RET_SUCCESS;
214}
215
216BOOLEAN XPL_FS_Exist(CPCHAR match_uri)
217{
218    struct  stat st;
219    bool result;
220
221
222    errno = 0;  // reset to 0
223
224    if(stat(match_uri, &st) < 0)
225      result = FALSE;
226    else
227      result = TRUE;
228
229    // XPL_LOG_DM_XPL_Debug(("XPL_FS_Exists: match uri %s, errno is %d result = %d\n",match_uri, errno, result));
230
231    return result;
232}
233
234BOOLEAN XPL_FS_CheckPermission(CPCHAR match_uri, XPL_FS_OPEN_MODE_T permission)
235{
236    bool result = FALSE;
237    int mode = 0;
238
239    switch (permission) {
240    case XPL_FS_RDONLY_MODE:
241      mode = R_OK;
242      break;
243    case XPL_FS_WRONLY_MODE:
244    case XPL_FS_RDWR_MODE:
245    case XPL_FS_CREAT_MODE:
246    case XPL_FS_TRUNC_MODE:
247    case XPL_FS_APPEND_MODE:
248      mode = R_OK | W_OK;
249      break;
250    default:
251      break;
252    }
253
254    errno = 0;  // reset to 0
255    if (access(match_uri, mode) == 0) {
256      result = TRUE;
257    }
258    //    XPL_LOG_DM_XPL_Debug(("XPL_FS_CheckPermission: match uri %s, errno is %d result = %d\n",match_uri, errno, result));
259
260    return result;
261}
262
263
264XPL_CLK_CLOCK_T XPL_FS_GetModTime(CPCHAR file_uri)
265{
266    struct stat st;
267
268    if(stat( file_uri, &st) < 0)
269      return 0;   // like it was never modified
270    else
271      return (XPL_CLK_CLOCK_T)st.st_mtime;
272 }
273
274XPL_FS_SIZE_T XPL_FS_GetSize(XPL_FS_HANDLE_T file_handle)
275{
276    struct stat st;
277
278    if(fstat(file_handle, &st) < 0)
279       return XPL_FS_SIZE_INVALID;
280    return st.st_size;
281}
282
283
284XPL_FS_RET_STATUS_T XPL_FS_MkDir(CPCHAR dir_uri)
285{
286    mkdir(dir_uri, S_IRWXU|S_IRWXG|S_IRWXO);
287    return XPL_FS_RET_SUCCESS;
288}
289
290XPL_FS_RET_STATUS_T XPL_FS_Lock(XPL_FS_HANDLE_T file_handle, BOOLEAN bLockExclusive )
291{
292    struct flock fl;
293
294    fl.l_type = bLockExclusive ? F_WRLCK : F_RDLCK;
295    fl.l_whence = SEEK_SET;
296    fl.l_start = 0;
297    fl.l_len = 0;
298    fl.l_pid = getpid();
299
300    if (fcntl(file_handle, F_SETLK, &fl) != -1)
301        return XPL_FS_RET_SUCCESS;
302    else
303        return (errno == EAGAIN ? XPL_FS_RET_TRYAGAIN : XPL_FS_RET_FAIL);
304}
305
306XPL_FS_RET_STATUS_T XPL_FS_Unlock(XPL_FS_HANDLE_T file_handle)
307{
308    struct flock fl;
309
310    fl.l_type = F_UNLCK;
311    fl.l_whence = SEEK_SET;
312    fl.l_start = 0;
313    fl.l_len = 0;
314    fl.l_pid = getpid();
315
316    if (fcntl(file_handle, F_SETLK, &fl) != -1)
317        return XPL_FS_RET_SUCCESS;
318    else
319        return XPL_FS_RET_FAIL;
320}
321
322
323XPL_FS_RET_STATUS_T XPL_FS_Unlink(CPCHAR file_name)
324{
325    if ( unlink(file_name) == 0 )
326        return XPL_FS_RET_SUCCESS;
327    else
328        return XPL_FS_RET_FAIL;
329}
330
331
332
333XPL_FS_SHANDLE_T XPL_FS_StartSearch(CPCHAR dir_uri, CPCHAR extension, BOOLEAN bFullName, XPL_FS_RET_STATUS_T * result)
334{
335     DIR *dir = XPL_NULL;
336
337     if ( result )
338         *result = XPL_FS_RET_SUCCESS;
339
340     dir = opendir(dir_uri);
341     if ( dir == NULL )
342     {
343        if ( result )
344            *result = XPL_FS_RET_FAIL;
345
346		return XPL_FS_SHANDLE_INVALID;
347     }
348
349     DMDirHandler * pDirHandler = NULL;
350     pDirHandler = new DMDirHandler;
351
352     if ( pDirHandler == NULL )
353     {
354        if ( result )
355            *result = XPL_FS_RET_FAIL;
356
357		closedir( dir );
358        return XPL_FS_SHANDLE_INVALID;
359     }
360
361     if ( bFullName )
362     {
363        int nDirLen = strlen(dir_uri);
364        if ( nDirLen >= XPL_FS_MAX_FILE_NAME_LENGTH )
365        {
366           return XPL_FS_SHANDLE_INVALID;
367        }
368        if (nDirLen>0)
369        {
370           pDirHandler->m_szDirectory = dir_uri;
371           if ( dir_uri[nDirLen-1] != '/' )
372           {
373              pDirHandler->m_szDirectory += "/";
374              ++nDirLen;
375           }
376           pDirHandler->m_nDirLen = nDirLen;
377        }
378     }
379
380     pDirHandler->m_szExtension = extension;
381     pDirHandler->m_pDir = dir;
382
383     return (XPL_FS_SHANDLE_T)(pDirHandler);
384}
385
386
387XPL_FS_RET_STATUS_T XPL_FS_GetSearchResult(XPL_FS_SHANDLE_T search_handle, XPL_FS_SEARCH_FILE file_name)
388{
389    DMDirHandler * pDirHandler = (DMDirHandler*)search_handle;
390    struct dirent *de = NULL;
391
392	if ( !pDirHandler || search_handle == XPL_FS_SHANDLE_INVALID )
393	  return XPL_FS_RET_FAIL;
394
395    int nNameLen = 0;
396    int nExtensionLen = strlen(pDirHandler->m_szExtension);
397    de = readdir(pDirHandler->m_pDir);
398    while ( de )
399    {
400        nNameLen = strlen(de->d_name);
401        if (nNameLen > nExtensionLen && !strncmp((de->d_name + nNameLen - nExtensionLen), pDirHandler->m_szExtension, nExtensionLen))
402        {
403          if ( pDirHandler->m_nDirLen+nNameLen >= XPL_FS_MAX_FILE_NAME_LENGTH )
404          {
405	    return XPL_FS_RET_FAIL;
406          }
407          if ( pDirHandler->m_nDirLen>0 )
408          {
409            strcpy(file_name,pDirHandler->m_szDirectory);
410          }
411          strcpy(file_name+pDirHandler->m_nDirLen,(CPCHAR)de->d_name);
412          return XPL_FS_RET_SUCCESS;
413        }
414        else
415        {
416          de = readdir(pDirHandler->m_pDir);
417        }
418    }
419
420    return XPL_FS_RET_NOT_FOUND;
421}
422
423
424XPL_FS_RET_STATUS_T XPL_FS_EndSearch(XPL_FS_SHANDLE_T search_handle)
425{
426    DMDirHandler * pDirHandler = (DMDirHandler*)search_handle;
427	// DO not call closedir(...); since it's called from DirHandle destructor...
428    delete pDirHandler;
429    return XPL_FS_RET_SUCCESS;
430}
431
432
433UINT8 * XPL_FS_MemMap(XPL_FS_HANDLE_T file_handle, UINT32 size, UINT32 offset, XPL_FS_RET_STATUS_T * result)
434{
435    UINT8 * pBuffer = NULL;
436
437    if ( result )
438        *result = XPL_FS_RET_SUCCESS;
439
440    pBuffer = (UINT8*)mmap(0,size,PROT_READ,MAP_PRIVATE,file_handle,offset);
441    if ( pBuffer == MAP_FAILED )
442    {
443         if ( result)
444             *result = XPL_FS_RET_FAIL;
445         return NULL;
446    }
447
448    return pBuffer;
449
450}
451
452
453XPL_FS_RET_STATUS_T XPL_FS_MemUnMap(UINT8 * pBuffer, UINT32 size)
454{
455    int res = munmap(pBuffer,size);
456    if ( res == 0 )
457        return XPL_FS_RET_SUCCESS;
458    else
459        return XPL_FS_RET_FAIL;
460}
461#ifdef LOB_SUPPORT
462static const char  TEMP_ESN_DIR_NAME[]= "/data/data/com.android.omadm.service/tmp/";
463CPCHAR XPL_FS_TempEsnDir()
464{
465 return TEMP_ESN_DIR_NAME;
466}
467XPL_FS_SIZE_T XPL_FS_FreeDiskSpace(CPCHAR pEsnDir)
468{
469  struct statfs sf;
470  XPL_FS_SIZE_T retSize = 0;
471
472  if(statfs(pEsnDir, &sf) == 0)
473  {
474    retSize = sf.f_bfree * sf.f_bsize;
475  }
476  return retSize;
477}
478#endif
479
480#ifdef __cplusplus
481}
482#endif
483