xref: /petsc/src/sys/fileio/fdir.c (revision d5b43468fb8780a8feea140ccd6fa3e6a50411cc)
1 #define PETSC_DESIRE_FEATURE_TEST_MACROS /* for lstat() */
2 #include <petscsys.h>
3 #include <sys/stat.h>
4 #if defined(PETSC_HAVE_DIRECT_H)
5   #include <direct.h>
6 #endif
7 #if defined(PETSC_HAVE_IO_H)
8   #include <io.h>
9 #endif
10 #if defined(PETSC_HAVE_STDINT_H)
11   #include <stdint.h>
12 #endif
13 #if defined(PETSC_HAVE_UNISTD_H) /* for mkdtemp */
14   #include <unistd.h>
15 #endif
16 
17 PetscErrorCode PetscPathJoin(const char dname[], const char fname[], size_t n, char fullname[])
18 {
19   size_t l1, l2;
20   PetscFunctionBegin;
21   PetscCall(PetscStrlen(dname, &l1));
22   PetscCall(PetscStrlen(fname, &l2));
23   PetscCheck((l1 + l2 + 2) <= n, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Path length is greater than buffer size");
24   PetscCall(PetscStrncpy(fullname, dname, n));
25   PetscCall(PetscStrlcat(fullname, "/", n));
26   PetscCall(PetscStrlcat(fullname, fname, n));
27   PetscFunctionReturn(0);
28 }
29 
30 PetscErrorCode PetscMkdir(const char dir[])
31 {
32   int       err;
33   PetscBool flg;
34 
35   PetscFunctionBegin;
36   PetscCall(PetscTestDirectory(dir, 'w', &flg));
37   if (flg) PetscFunctionReturn(0);
38 #if defined(PETSC_HAVE__MKDIR) && defined(PETSC_HAVE_DIRECT_H)
39   err = _mkdir(dir);
40 #else
41   err = mkdir(dir, S_IRWXU | S_IRGRP | S_IXGRP);
42 #endif
43   PetscCheck(!err, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Could not create dir: %s", dir);
44   PetscFunctionReturn(0);
45 }
46 
47 #if defined(PETSC_USING_DARWIN) && defined(PETSC_HAVE_FSTATAT)
48   /*
49     Apple's mkdtemp() crashes under Valgrind so this replaces it with a version that does not crash under valgrind
50 */
51   #include "apple_fdir.h"
52 #endif
53 
54 /*@C
55   PetscMkdtemp - Create a folder with a unique name given a filename template.
56 
57   Not Collective
58 
59   Input Parameters:
60 . dir - file name template, the last six characters must be 'XXXXXX', and they will be modified upon return
61 
62   Level: developer
63 
64 .seealso: `PetscMkdir()`
65 @*/
66 PetscErrorCode PetscMkdtemp(char dir[])
67 {
68   PetscFunctionBegin;
69 #if defined(PETSC_HAVE_WINDOWS_H) && defined(PETSC_HAVE_IO_H) && defined(PETSC_HAVE__MKDIR) && defined(PETSC_HAVE_DIRECT_H)
70   {
71     int      err = 1;
72     char     name[PETSC_MAX_PATH_LEN];
73     PetscInt i = 0, max_retry = 26;
74     size_t   len;
75 
76     while (err && i < max_retry) {
77       PetscCall(PetscStrncpy(name, dir, sizeof(name)));
78       PetscCall(PetscStrlen(name, &len));
79       err = _mktemp_s(name, len + 1);
80       PetscCheck(!err, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Could not generate a unique name using the template: %s", dir);
81       err = _mkdir(name);
82       i++;
83     }
84     PetscCheck(!err, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Exceeds maximum retry time when creating temporary dir using the template: %s", dir);
85     PetscCall(PetscStrncpy(dir, name, len + 1));
86   }
87 #else
88   dir = mkdtemp(dir);
89   PetscCheck(dir, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Could not create temporary dir");
90 #endif
91   PetscFunctionReturn(0);
92 }
93 
94 #if defined(PETSC_HAVE_DIRECT_H)
95 PetscErrorCode PetscRMTree(const char dir[])
96 {
97   struct _finddata_t data;
98   char               loc[PETSC_MAX_PATH_LEN];
99   PetscBool          flg1, flg2;
100   #if defined(PETSC_HAVE_STDINT_H)
101   intptr_t handle;
102   #else
103   long handle;
104   #endif
105 
106   PetscFunctionBegin;
107   PetscCall(PetscPathJoin(dir, "*", PETSC_MAX_PATH_LEN, loc));
108   handle = _findfirst(loc, &data);
109   if (handle == -1) {
110     PetscBool flg;
111     PetscCall(PetscTestDirectory(loc, 'r', &flg));
112     PetscCheck(!flg, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Cannot access directory to delete: %s", dir);
113     PetscCall(PetscTestFile(loc, 'r', &flg));
114     PetscCheck(!flg, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Specified path is a file - not a dir: %s", dir);
115     PetscFunctionReturn(0); /* perhaps the dir was not yet created */
116   }
117   while (_findnext(handle, &data) != -1) {
118     PetscCall(PetscStrcmp(data.name, ".", &flg1));
119     PetscCall(PetscStrcmp(data.name, "..", &flg2));
120     if (flg1 || flg2) continue;
121     PetscCall(PetscPathJoin(dir, data.name, PETSC_MAX_PATH_LEN, loc));
122     if (data.attrib & _A_SUBDIR) {
123       PetscCall(PetscRMTree(loc));
124     } else {
125       PetscCheck(!remove(loc), PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Could not delete file: %s", loc);
126     }
127   }
128   _findclose(handle);
129   PetscCheck(!_rmdir(dir), PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Could not delete dir: %s", dir);
130   PetscFunctionReturn(0);
131 }
132 #else
133   #include <dirent.h>
134   #include <unistd.h>
135 PetscErrorCode PetscRMTree(const char dir[])
136 {
137   struct dirent *data;
138   char loc[PETSC_MAX_PATH_LEN];
139   PetscBool flg1, flg2;
140   DIR *dirp;
141   struct stat statbuf;
142 
143   PetscFunctionBegin;
144   dirp = opendir(dir);
145   if (!dirp) {
146     PetscBool flg;
147     PetscCall(PetscTestDirectory(dir, 'r', &flg));
148     PetscCheck(!flg, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Cannot access directory to delete: %s", dir);
149     PetscCall(PetscTestFile(dir, 'r', &flg));
150     PetscCheck(!flg, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Specified path is a file - not a dir: %s", dir);
151     PetscFunctionReturn(0); /* perhaps the dir was not yet created */
152   }
153   while ((data = readdir(dirp))) {
154     PetscCall(PetscStrcmp(data->d_name, ".", &flg1));
155     PetscCall(PetscStrcmp(data->d_name, "..", &flg2));
156     if (flg1 || flg2) continue;
157     PetscCall(PetscPathJoin(dir, data->d_name, PETSC_MAX_PATH_LEN, loc));
158     PetscCheck(lstat(loc, &statbuf) >= 0, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "cannot run lstat() on: %s", loc);
159     if (S_ISDIR(statbuf.st_mode)) {
160       PetscCall(PetscRMTree(loc));
161     } else {
162       PetscCheck(!unlink(loc), PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Could not delete file: %s", loc);
163     }
164   }
165   closedir(dirp);
166   PetscCheck(!rmdir(dir), PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Could not delete dir: %s", dir);
167   PetscFunctionReturn(0);
168 }
169 #endif
170