| // Licensed to the Apache Software Foundation (ASF) under one |
| // or more contributor license agreements. See the NOTICE file |
| // distributed with this work for additional information |
| // regarding copyright ownership. The ASF licenses this file |
| // to you under the Apache License, Version 2.0 (the |
| // "License"); you may not use this file except in compliance |
| // with the License. You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, |
| // software distributed under the License is distributed on an |
| // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| // KIND, either express or implied. See the License for the |
| // specific language governing permissions and limitations |
| // under the License. |
| |
| #include "DFPlatform.h" |
| #include <errno.h> |
| #include <stdlib.h> |
| #include <string.h> |
| #include <stdio.h> |
| #include <sys/stat.h> |
| |
| // This file contains functions that are applicable to all Unix-based platforms, including Linux, iOS, and OS X |
| |
| #ifndef _WINDOWS |
| |
| #include <pthread.h> |
| #include <dirent.h> |
| |
| static int testAndSet(int *var, int value, pthread_mutex_t *lock) |
| { |
| pthread_mutex_lock(lock); |
| int oldValue = *var; |
| *var = value; |
| pthread_mutex_unlock(lock); |
| return oldValue; |
| } |
| |
| void DFInitOnce(DFOnce *once, DFOnceFunction fun) |
| { |
| static pthread_mutex_t onceLock = PTHREAD_MUTEX_INITIALIZER; |
| if (testAndSet(once,1,&onceLock) == 0) |
| fun(); |
| } |
| |
| int DFMkdirIfAbsent(const char *path, char **errmsg) |
| { |
| if ((mkdir(path,0777) != 0) && (errno != EEXIST)) { |
| printf("DFMkdirIfAbsent: errno = %d (%s)\n",errno,strerror(errno)); |
| if (errmsg != NULL) |
| *errmsg = xstrdup(strerror(errno)); |
| return 0; |
| } |
| return 1; |
| } |
| |
| int DFAddDirContents(const char *absPath, const char *relPath, int recursive, DFDirEntryList ***list, char **errmsg) |
| { |
| DFDirEntryList **listptr = *list; |
| |
| DIR *dir = opendir(absPath); |
| if (dir == NULL) { |
| if (errmsg != NULL) { |
| char temp[1024]; |
| snprintf(temp,1024,"%s: %s",relPath,strerror(errno)); |
| *errmsg = xstrdup(temp); |
| } |
| return 0; |
| } |
| |
| struct dirent buffer; |
| struct dirent *result = NULL; |
| int ok = 1; |
| while (ok && (0 == readdir_r(dir,&buffer,&result)) && (result != NULL)) { |
| if (!strcmp(result->d_name,".") || !strcmp(result->d_name,"..")) |
| continue; |
| |
| size_t absSubPathLen = strlen(absPath) + 1 + strlen(result->d_name); |
| size_t relSubPathLen = strlen(relPath) + 1 + strlen(result->d_name); |
| |
| char *absSubPath = (char *)xmalloc(absSubPathLen+1); |
| char *relSubPath = (char *)xmalloc(relSubPathLen+1); |
| |
| snprintf(absSubPath,absSubPathLen+1,"%s/%s",absPath,result->d_name); |
| snprintf(relSubPath,relSubPathLen+1,"%s/%s",relPath,result->d_name); |
| |
| char *entryName; |
| if (relSubPath[0] == '/') |
| entryName = &relSubPath[1]; |
| else |
| entryName = relSubPath; |
| |
| *listptr = (DFDirEntryList *)xcalloc(1,sizeof(DFDirEntryList)); |
| (*listptr)->name = xstrdup(entryName); |
| listptr = &(*listptr)->next; |
| |
| struct stat statbuf; |
| if (recursive && (0 == stat(absSubPath,&statbuf)) && S_ISDIR(statbuf.st_mode)) |
| ok = DFAddDirContents(absSubPath,relSubPath,recursive,&listptr,errmsg); |
| |
| free(absSubPath); |
| free(relSubPath); |
| } |
| closedir(dir); |
| *list = listptr; |
| return ok; |
| } |
| |
| #endif |