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