BRL-CAD
file.c
Go to the documentation of this file.
1 /* F I L E . C
2  * BRL-CAD
3  *
4  * Copyright (c) 2004-2014 United States Government as represented by
5  * the U.S. Army Research Laboratory.
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public License
9  * version 2.1 as published by the Free Software Foundation.
10  *
11  * This library is distributed in the hope that it will be useful, but
12  * WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this file; see the file named COPYING for more
18  * information.
19  */
20 
21 #include "common.h"
22 
23 #include <string.h>
24 #include <ctype.h>
25 #ifdef HAVE_SYS_TYPES_H
26 # include <sys/types.h>
27 #endif
28 #ifdef HAVE_SYS_STAT_H
29 # include <sys/stat.h>
30 #endif
31 #ifdef HAVE_PWD_H
32 # include <pwd.h>
33 #endif
34 #ifdef HAVE_GRP_H
35 # include <grp.h>
36 #endif
37 
38 #include "bio.h"
39 
40 #include "bu/debug.h"
41 #include "bu/file.h"
42 #include "bu/log.h"
43 #include "bu/str.h"
44 
45 #ifndef R_OK
46 # define R_OK 4
47 #endif
48 #ifndef W_OK
49 # define W_OK 2
50 #endif
51 #ifndef X_OK
52 # define X_OK 1
53 #endif
54 
55 
56 int
57 bu_file_exists(const char *path, int *fd)
58 {
59  struct stat sbuf;
60 
62  bu_log("Does [%s] exist? ", path);
63  }
64 
65  if (!path || path[0] == '\0') {
66  if (UNLIKELY(bu_debug & BU_DEBUG_PATHS)) {
67  bu_log("NO\n");
68  }
69  /* FAIL */
70  return 0;
71  }
72 
73  /* capture file descriptor if requested */
74  if (fd) {
75  *fd = open(path, O_RDONLY);
76  if (UNLIKELY(bu_debug & BU_DEBUG_PATHS)) {
77  bu_log("YES\n");
78  }
79  /* OK */
80  return 1;
81  }
82 
83  /* does it exist as a filesystem entity? */
84  if (stat(path, &sbuf) == 0) {
85  if (UNLIKELY(bu_debug & BU_DEBUG_PATHS)) {
86  bu_log("YES\n");
87  }
88  /* OK */
89  return 1;
90  }
91 
92  if (UNLIKELY(bu_debug & BU_DEBUG_PATHS)) {
93  bu_log("NO\n");
94  }
95  /* FAIL */
96  return 0;
97 }
98 
99 
100 int
101 bu_same_file(const char *fn1, const char *fn2)
102 {
103  struct stat sb1, sb2;
104 
105  if (UNLIKELY(!fn1 || !fn2)) {
106  return 0;
107  }
108 
109  if (UNLIKELY(fn1[0] == '\0' || fn2[0] == '\0')) {
110  return 0;
111  }
112 
113  if (!bu_file_exists(fn1, NULL) || !bu_file_exists(fn2, NULL)) {
114  return 0;
115  }
116 
117  if ((stat(fn1, &sb1) == 0) &&
118  (stat(fn2, &sb2) == 0) &&
119  (sb1.st_dev == sb2.st_dev) &&
120  (sb1.st_ino == sb2.st_ino)) {
121  return 1;
122  }
123 
124  return 0;
125 }
126 
127 
128 int
129 bu_same_fd(int fd1, int fd2)
130 {
131  struct stat sb1, sb2;
132 
133  if (UNLIKELY(fd1<0 || fd2<0)) {
134  return 0;
135  }
136 
137  /* ares files the same inode on same device? */
138  if ((fstat(fd1, &sb1) == 0) && (fstat(fd2, &sb2) == 0) && (sb1.st_dev == sb2.st_dev) && (sb1.st_ino == sb2.st_ino)) {
139  return 1;
140  }
141 
142  return 0;
143 }
144 
145 
146 /**
147  * common guts to the file access functions that returns truthfully if
148  * the current user has the ability permission-wise to access the
149  * specified file.
150  */
151 HIDDEN int
152 file_access(const char *path, int access_level)
153 {
154  struct stat sb;
155  int mask = 0;
156 
157  /* 0 is root or Windows user */
158  uid_t uid = 0;
159 
160  /* 0 is wheel or Windows group */
161  gid_t gid = 0;
162 
163  int usr_mask = S_IRUSR | S_IWUSR | S_IXUSR;
164  int grp_mask = S_IRGRP | S_IWGRP | S_IXGRP;
165  int oth_mask = S_IROTH | S_IWOTH | S_IXOTH;
166 
167  if (UNLIKELY(!path || (path[0] == '\0'))) {
168  return 0;
169  }
170 
171  if (stat(path, &sb) == -1) {
172  return 0;
173  }
174 
175  if (access_level & R_OK) {
176  mask = S_IRUSR | S_IRGRP | S_IROTH;
177  }
178  if (access_level & W_OK) {
179  mask = S_IWUSR | S_IWGRP | S_IWOTH;
180  }
181  if (access_level & X_OK) {
182  mask = S_IXUSR | S_IXGRP | S_IXOTH;
183  }
184 
185 #ifdef HAVE_GETEUID
186  uid = geteuid();
187 #endif
188 #ifdef HAVE_GETEGID
189  gid = getegid();
190 #endif
191 
192  if ((uid_t)sb.st_uid == uid) {
193  /* we own it */
194  return sb.st_mode & (mask & usr_mask);
195  } else if ((gid_t)sb.st_gid == gid) {
196  /* our primary group */
197  return sb.st_mode & (mask & grp_mask);
198  }
199 
200  /* search group database to see if we're in the file's group */
201 #if defined(HAVE_PWD_H) && defined (HAVE_GRP_H)
202  {
203  struct passwd *pwdb = getpwuid(uid);
204  if (pwdb && pwdb->pw_name) {
205  int i;
206  struct group *grdb = getgrgid(sb.st_gid);
207  for (i = 0; grdb && grdb->gr_mem[i]; i++) {
208  if (BU_STR_EQUAL(grdb->gr_mem[i], pwdb->pw_name)) {
209  /* one of our other groups */
210  return sb.st_mode & (mask & grp_mask);
211  }
212  }
213  }
214  }
215 #endif
216 
217  /* check other */
218  return sb.st_mode & (mask & oth_mask);
219 }
220 
221 
222 int
223 bu_file_readable(const char *path)
224 {
225  return file_access(path, R_OK);
226 }
227 
228 
229 int
230 bu_file_writable(const char *path)
231 {
232  return file_access(path, W_OK);
233 }
234 
235 
236 int
237 bu_file_executable(const char *path)
238 {
239  return file_access(path, X_OK);
240 }
241 
242 
243 int
244 bu_file_directory(const char *path)
245 {
246  struct stat sb;
247 
248  if (UNLIKELY(!path || (path[0] == '\0'))) {
249  return 0;
250  }
251 
252  if (stat(path, &sb) == -1) {
253  return 0;
254  }
255 
256  return (S_ISDIR(sb.st_mode));
257 }
258 
259 
260 int
261 bu_file_symbolic(const char *path)
262 {
263  struct stat sb;
264 
265  if (UNLIKELY(!path || (path[0] == '\0'))) {
266  return 0;
267  }
268 
269  if (stat(path, &sb) == -1) {
270  return 0;
271  }
272 
273  return (S_ISLNK(sb.st_mode));
274 }
275 
276 
277 int
278 bu_file_delete(const char *path)
279 {
280  int fd = 0;
281  int ret = 0;
282  int retry = 0;
283  struct stat sb;
284 
285  /* reject empty, special, or non-existent paths */
286  if (!path
287  || BU_STR_EQUAL(path, "")
288  || BU_STR_EQUAL(path, ".")
289  || BU_STR_EQUAL(path, "..")
290  || !bu_file_exists(path, &fd))
291  {
292  return 0;
293  }
294 
295  do {
296 
297  if (retry++) {
298  /* second pass, try to force deletion by changing file
299  * permissions (similar to rm -f).
300  */
301  if (fstat(fd, &sb) == -1) {
302  break;
303  }
304  bu_fchmod(fd, (sb.st_mode|S_IRWXU));
305  }
306 
307  ret = (remove(path) == 0) ? 0 : 1;
308 
309  } while (ret == 0 && retry < 2);
310  close(fd);
311 
312  /* all boils down to whether the file still exists, not whether
313  * remove thinks it succeeded.
314  */
315  if (bu_file_exists(path, &fd)) {
316  /* failure */
317  if (retry > 1) {
318  /* restore original file permission */
319  bu_fchmod(fd, sb.st_mode);
320  }
321  close(fd);
322  return 0;
323  } else {
324  /* deleted */
325  return 1;
326  }
327 }
328 
329 int
330 bu_fseek(FILE *stream, off_t offset, int origin)
331 {
332  int ret;
333 
334 #if defined(HAVE__FSEEKI64) && defined(SIZEOF_VOID_P) && SIZEOF_VOID_P == 8
335  ret = _fseeki64(stream, offset, origin);
336 #else
337  ret = fseek(stream, offset, origin);
338 #endif
339 
340  return ret;
341 }
342 
343 off_t
344 bu_ftell(FILE *stream)
345 {
346  off_t ret;
347 
348 #if defined(HAVE__FTELLI64) && defined(SIZEOF_VOID_P) && SIZEOF_VOID_P == 8
349  /* windows 64bit */
350  ret = _ftelli64(stream);
351 #else
352  ret = ftell(stream);
353 #endif
354 
355  return ret;
356 }
357 
358 /*
359  * Local Variables:
360  * mode: C
361  * tab-width: 8
362  * indent-tabs-mode: t
363  * c-file-style: "stroustrup"
364  * End:
365  * ex: shiftwidth=4 tabstop=8
366  */
void bu_log(const char *,...) _BU_ATTR_PRINTF12
Definition: log.c:176
int bu_fchmod(int fd, unsigned long pmode)
Definition: fchmod.c:131
off_t bu_ftell(FILE *stream)
Definition: file.c:344
#define W_OK
Definition: file.c:49
int bu_fseek(FILE *stream, off_t offset, int origin)
Definition: file.c:330
Header file for the BRL-CAD common definitions.
int bu_file_readable(const char *path)
Definition: file.c:223
#define X_OK
Definition: file.c:52
#define BU_DEBUG_PATHS
Definition: debug.h:68
#define HIDDEN
Definition: common.h:86
int bu_file_writable(const char *path)
Definition: file.c:230
int bu_file_symbolic(const char *path)
Definition: file.c:261
int bu_same_file(const char *fn1, const char *fn2)
Definition: file.c:101
int bu_file_directory(const char *path)
Definition: file.c:244
int bu_debug
Definition: globals.c:87
int bu_same_fd(int fd1, int fd2)
Definition: file.c:129
#define R_OK
Definition: file.c:46
HIDDEN int file_access(const char *path, int access_level)
Definition: file.c:152
int bu_file_executable(const char *path)
Definition: file.c:237
int bu_file_exists(const char *path, int *fd)
Definition: file.c:57
int bu_file_delete(const char *path)
Definition: file.c:278
#define UNLIKELY(expression)
Definition: common.h:282
#define BU_STR_EQUAL(s1, s2)
Definition: str.h:126