xref: /petsc/src/sys/fileio/fdir.c (revision 21e3ffae2f3b73c0bd738cf6d0a809700fc04bb0)
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(PETSC_SUCCESS);
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(PETSC_SUCCESS);
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(PETSC_SUCCESS);
45 }
46 
47 /*@C
48   PetscMkdtemp - Create a folder with a unique name given a filename template.
49 
50   Not Collective
51 
52   Input Parameters:
53 . dir - file name template, the last six characters must be 'XXXXXX', and they will be modified upon return
54 
55   Level: developer
56 
57 .seealso: `PetscMkdir()`
58 @*/
59 PetscErrorCode PetscMkdtemp(char dir[])
60 {
61   PetscFunctionBegin;
62 #if defined(PETSC_HAVE_WINDOWS_H) && defined(PETSC_HAVE_IO_H) && defined(PETSC_HAVE__MKDIR) && defined(PETSC_HAVE_DIRECT_H)
63   {
64     int      err = 1;
65     char     name[PETSC_MAX_PATH_LEN];
66     PetscInt i = 0, max_retry = 26;
67     size_t   len;
68 
69     while (err && i < max_retry) {
70       PetscCall(PetscStrncpy(name, dir, sizeof(name)));
71       PetscCall(PetscStrlen(name, &len));
72       err = _mktemp_s(name, len + 1);
73       PetscCheck(!err, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Could not generate a unique name using the template: %s", dir);
74       err = _mkdir(name);
75       i++;
76     }
77     PetscCheck(!err, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Exceeds maximum retry time when creating temporary dir using the template: %s", dir);
78     PetscCall(PetscStrncpy(dir, name, len + 1));
79   }
80 #else
81   dir = mkdtemp(dir);
82   PetscCheck(dir, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Could not create temporary dir");
83 #endif
84   PetscFunctionReturn(PETSC_SUCCESS);
85 }
86 
87 #if defined(PETSC_HAVE_DIRECT_H)
88 PetscErrorCode PetscRMTree(const char dir[])
89 {
90   struct _finddata_t data;
91   char               loc[PETSC_MAX_PATH_LEN];
92   PetscBool          flg1, flg2;
93   #if defined(PETSC_HAVE_STDINT_H)
94   intptr_t handle;
95   #else
96   long handle;
97   #endif
98 
99   PetscFunctionBegin;
100   PetscCall(PetscPathJoin(dir, "*", PETSC_MAX_PATH_LEN, loc));
101   handle = _findfirst(loc, &data);
102   if (handle == -1) {
103     PetscBool flg;
104     PetscCall(PetscTestDirectory(loc, 'r', &flg));
105     PetscCheck(!flg, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Cannot access directory to delete: %s", dir);
106     PetscCall(PetscTestFile(loc, 'r', &flg));
107     PetscCheck(!flg, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Specified path is a file - not a dir: %s", dir);
108     PetscFunctionReturn(PETSC_SUCCESS); /* perhaps the dir was not yet created */
109   }
110   while (_findnext(handle, &data) != -1) {
111     PetscCall(PetscStrcmp(data.name, ".", &flg1));
112     PetscCall(PetscStrcmp(data.name, "..", &flg2));
113     if (flg1 || flg2) continue;
114     PetscCall(PetscPathJoin(dir, data.name, PETSC_MAX_PATH_LEN, loc));
115     if (data.attrib & _A_SUBDIR) {
116       PetscCall(PetscRMTree(loc));
117     } else {
118       PetscCheck(!remove(loc), PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Could not delete file: %s", loc);
119     }
120   }
121   _findclose(handle);
122   PetscCheck(!_rmdir(dir), PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Could not delete dir: %s", dir);
123   PetscFunctionReturn(PETSC_SUCCESS);
124 }
125 #else
126   #include <dirent.h>
127   #include <unistd.h>
128 PetscErrorCode PetscRMTree(const char dir[])
129 {
130   struct dirent *data;
131   char loc[PETSC_MAX_PATH_LEN];
132   PetscBool flg1, flg2;
133   DIR *dirp;
134   struct stat statbuf;
135 
136   PetscFunctionBegin;
137   dirp = opendir(dir);
138   if (!dirp) {
139     PetscBool flg;
140     PetscCall(PetscTestDirectory(dir, 'r', &flg));
141     PetscCheck(!flg, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Cannot access directory to delete: %s", dir);
142     PetscCall(PetscTestFile(dir, 'r', &flg));
143     PetscCheck(!flg, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Specified path is a file - not a dir: %s", dir);
144     PetscFunctionReturn(PETSC_SUCCESS); /* perhaps the dir was not yet created */
145   }
146   while ((data = readdir(dirp))) {
147     PetscCall(PetscStrcmp(data->d_name, ".", &flg1));
148     PetscCall(PetscStrcmp(data->d_name, "..", &flg2));
149     if (flg1 || flg2) continue;
150     PetscCall(PetscPathJoin(dir, data->d_name, PETSC_MAX_PATH_LEN, loc));
151     PetscCheck(lstat(loc, &statbuf) >= 0, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "cannot run lstat() on: %s", loc);
152     if (S_ISDIR(statbuf.st_mode)) {
153       PetscCall(PetscRMTree(loc));
154     } else {
155       PetscCheck(!unlink(loc), PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Could not delete file: %s", loc);
156     }
157   }
158   closedir(dirp);
159   PetscCheck(!rmdir(dir), PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Could not delete dir: %s", dir);
160   PetscFunctionReturn(PETSC_SUCCESS);
161 }
162 #endif
163