Blender  V2.93
BLI_filelist.c
Go to the documentation of this file.
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  */
16 
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <sys/types.h>
24 
25 #ifndef WIN32
26 # include <dirent.h>
27 #endif
28 
29 #include <string.h> /* strcpy etc.. */
30 #include <sys/stat.h>
31 #include <time.h>
32 
33 #ifdef WIN32
34 # include "BLI_winstuff.h"
35 # include "utfconv.h"
36 # include <direct.h>
37 # include <io.h>
38 #else
39 # include <pwd.h>
40 # include <sys/ioctl.h>
41 # include <unistd.h>
42 #endif
43 
44 /* lib includes */
45 #include "MEM_guardedalloc.h"
46 
47 #include "DNA_listBase.h"
48 
49 #include "BLI_fileops.h"
50 #include "BLI_fileops_types.h"
51 #include "BLI_listbase.h"
52 #include "BLI_path_util.h"
53 #include "BLI_string.h"
54 
55 #include "../imbuf/IMB_imbuf.h"
56 
57 /*
58  * Ordering function for sorting lists of files/directories. Returns -1 if
59  * entry1 belongs before entry2, 0 if they are equal, 1 if they should be swapped.
60  */
61 static int bli_compare(struct direntry *entry1, struct direntry *entry2)
62 {
63  /* type is equal to stat.st_mode */
64 
65  /* directories come before non-directories */
66  if (S_ISDIR(entry1->type)) {
67  if (S_ISDIR(entry2->type) == 0) {
68  return -1;
69  }
70  }
71  else {
72  if (S_ISDIR(entry2->type)) {
73  return 1;
74  }
75  }
76  /* non-regular files come after regular files */
77  if (S_ISREG(entry1->type)) {
78  if (S_ISREG(entry2->type) == 0) {
79  return -1;
80  }
81  }
82  else {
83  if (S_ISREG(entry2->type)) {
84  return 1;
85  }
86  }
87  /* arbitrary, but consistent, ordering of different types of non-regular files */
88  if ((entry1->type & S_IFMT) < (entry2->type & S_IFMT)) {
89  return -1;
90  }
91  if ((entry1->type & S_IFMT) > (entry2->type & S_IFMT)) {
92  return 1;
93  }
94 
95  /* OK, now we know their S_IFMT fields are the same, go on to a name comparison */
96  /* make sure "." and ".." are always first */
97  if (FILENAME_IS_CURRENT(entry1->relname)) {
98  return -1;
99  }
100  if (FILENAME_IS_CURRENT(entry2->relname)) {
101  return 1;
102  }
103  if (FILENAME_IS_PARENT(entry1->relname)) {
104  return -1;
105  }
106  if (FILENAME_IS_PARENT(entry2->relname)) {
107  return 1;
108  }
109 
110  return (BLI_strcasecmp_natural(entry1->relname, entry2->relname));
111 }
112 
113 struct BuildDirCtx {
114  struct direntry *files; /* array[nrfiles] */
115  int nrfiles;
116 };
117 
121 static void bli_builddir(struct BuildDirCtx *dir_ctx, const char *dirname)
122 {
123  struct ListBase dirbase = {NULL, NULL};
124  int newnum = 0;
125  DIR *dir;
126 
127  if ((dir = opendir(dirname)) != NULL) {
128  const struct dirent *fname;
129  bool has_current = false, has_parent = false;
130 
131  while ((fname = readdir(dir)) != NULL) {
132  struct dirlink *const dlink = (struct dirlink *)malloc(sizeof(struct dirlink));
133  if (dlink != NULL) {
134  dlink->name = BLI_strdup(fname->d_name);
135  if (FILENAME_IS_PARENT(dlink->name)) {
136  has_parent = true;
137  }
138  else if (FILENAME_IS_CURRENT(dlink->name)) {
139  has_current = true;
140  }
141  BLI_addhead(&dirbase, dlink);
142  newnum++;
143  }
144  }
145 
146  if (!has_parent) {
147  char pardir[FILE_MAXDIR];
148 
149  BLI_strncpy(pardir, dirname, sizeof(pardir));
150  if (BLI_path_parent_dir(pardir) && (BLI_access(pardir, R_OK) == 0)) {
151  struct dirlink *const dlink = (struct dirlink *)malloc(sizeof(struct dirlink));
152  if (dlink != NULL) {
153  dlink->name = BLI_strdup(FILENAME_PARENT);
154  BLI_addhead(&dirbase, dlink);
155  newnum++;
156  }
157  }
158  }
159  if (!has_current) {
160  struct dirlink *const dlink = (struct dirlink *)malloc(sizeof(struct dirlink));
161  if (dlink != NULL) {
162  dlink->name = BLI_strdup(FILENAME_CURRENT);
163  BLI_addhead(&dirbase, dlink);
164  newnum++;
165  }
166  }
167 
168  if (newnum) {
169  if (dir_ctx->files) {
170  void *const tmp = MEM_reallocN(dir_ctx->files,
171  (dir_ctx->nrfiles + newnum) * sizeof(struct direntry));
172  if (tmp) {
173  dir_ctx->files = (struct direntry *)tmp;
174  }
175  else { /* realloc fail */
176  MEM_freeN(dir_ctx->files);
177  dir_ctx->files = NULL;
178  }
179  }
180 
181  if (dir_ctx->files == NULL) {
182  dir_ctx->files = (struct direntry *)MEM_mallocN(newnum * sizeof(struct direntry),
183  __func__);
184  }
185 
186  if (dir_ctx->files) {
187  struct dirlink *dlink = (struct dirlink *)dirbase.first;
188  struct direntry *file = &dir_ctx->files[dir_ctx->nrfiles];
189  while (dlink) {
190  char fullname[PATH_MAX];
191  memset(file, 0, sizeof(struct direntry));
192  file->relname = dlink->name;
193  file->path = BLI_strdupcat(dirname, dlink->name);
194  BLI_join_dirfile(fullname, sizeof(fullname), dirname, dlink->name);
195  if (BLI_stat(fullname, &file->s) != -1) {
196  file->type = file->s.st_mode;
197  }
198  else if (FILENAME_IS_CURRPAR(file->relname)) {
199  /* Hack around for UNC paths on windows:
200  * does not support stat on '\\SERVER\foo\..', sigh... */
201  file->type |= S_IFDIR;
202  }
203  dir_ctx->nrfiles++;
204  file++;
205  dlink = dlink->next;
206  }
207  }
208  else {
209  printf("Couldn't get memory for dir\n");
210  exit(1);
211  }
212 
213  BLI_freelist(&dirbase);
214  if (dir_ctx->files) {
215  qsort(dir_ctx->files,
216  dir_ctx->nrfiles,
217  sizeof(struct direntry),
218  (int (*)(const void *, const void *))bli_compare);
219  }
220  }
221  else {
222  printf("%s empty directory\n", dirname);
223  }
224 
225  closedir(dir);
226  }
227  else {
228  printf("%s non-existent directory\n", dirname);
229  }
230 }
231 
238 unsigned int BLI_filelist_dir_contents(const char *dirname, struct direntry **r_filelist)
239 {
240  struct BuildDirCtx dir_ctx;
241 
242  dir_ctx.nrfiles = 0;
243  dir_ctx.files = NULL;
244 
245  bli_builddir(&dir_ctx, dirname);
246 
247  if (dir_ctx.files) {
248  *r_filelist = dir_ctx.files;
249  }
250  else {
251  /* Keep Blender happy. Blender stores this in a variable
252  * where 0 has special meaning..... */
253  *r_filelist = MEM_mallocN(sizeof(**r_filelist), __func__);
254  }
255 
256  return dir_ctx.nrfiles;
257 }
258 
262 void BLI_filelist_entry_size_to_string(const struct stat *st,
263  const uint64_t sz,
264  /* Used to change MB -> M, etc. - is that really useful? */
265  const bool UNUSED(compact),
266  char r_size[FILELIST_DIRENTRY_SIZE_LEN])
267 {
268  /*
269  * Seems st_size is signed 32-bit value in *nix and Windows. This
270  * will buy us some time until files get bigger than 4GB or until
271  * everyone starts using __USE_FILE_OFFSET64 or equivalent.
272  */
273  double size = (double)(st ? st->st_size : sz);
274 #ifdef WIN32
275  BLI_str_format_byte_unit(r_size, size, false);
276 #else
277  BLI_str_format_byte_unit(r_size, size, true);
278 #endif
279 }
280 
284 void BLI_filelist_entry_mode_to_string(const struct stat *st,
285  const bool UNUSED(compact),
286  char r_mode1[FILELIST_DIRENTRY_MODE_LEN],
287  char r_mode2[FILELIST_DIRENTRY_MODE_LEN],
288  char r_mode3[FILELIST_DIRENTRY_MODE_LEN])
289 {
290  const char *types[8] = {"---", "--x", "-w-", "-wx", "r--", "r-x", "rw-", "rwx"};
291 
292 #ifdef WIN32
293  BLI_strncpy(r_mode1, types[0], sizeof(*r_mode1) * FILELIST_DIRENTRY_MODE_LEN);
294  BLI_strncpy(r_mode2, types[0], sizeof(*r_mode2) * FILELIST_DIRENTRY_MODE_LEN);
295  BLI_strncpy(r_mode3, types[0], sizeof(*r_mode3) * FILELIST_DIRENTRY_MODE_LEN);
296 #else
297  const int mode = st->st_mode;
298 
299  BLI_strncpy(r_mode1, types[(mode & 0700) >> 6], sizeof(*r_mode1) * FILELIST_DIRENTRY_MODE_LEN);
300  BLI_strncpy(r_mode2, types[(mode & 0070) >> 3], sizeof(*r_mode2) * FILELIST_DIRENTRY_MODE_LEN);
301  BLI_strncpy(r_mode3, types[(mode & 0007)], sizeof(*r_mode3) * FILELIST_DIRENTRY_MODE_LEN);
302 
303  if (((mode & S_ISGID) == S_ISGID) && (r_mode2[2] == '-')) {
304  r_mode2[2] = 'l';
305  }
306 
307  if (mode & (S_ISUID | S_ISGID)) {
308  if (r_mode1[2] == 'x') {
309  r_mode1[2] = 's';
310  }
311  else {
312  r_mode1[2] = 'S';
313  }
314 
315  if (r_mode2[2] == 'x') {
316  r_mode2[2] = 's';
317  }
318  }
319 
320  if (mode & S_ISVTX) {
321  if (r_mode3[2] == 'x') {
322  r_mode3[2] = 't';
323  }
324  else {
325  r_mode3[2] = 'T';
326  }
327  }
328 #endif
329 }
330 
334 void BLI_filelist_entry_owner_to_string(const struct stat *st,
335  const bool UNUSED(compact),
336  char r_owner[FILELIST_DIRENTRY_OWNER_LEN])
337 {
338 #ifdef WIN32
339  strcpy(r_owner, "unknown");
340 #else
341  struct passwd *pwuser = getpwuid(st->st_uid);
342 
343  if (pwuser) {
344  BLI_strncpy(r_owner, pwuser->pw_name, sizeof(*r_owner) * FILELIST_DIRENTRY_OWNER_LEN);
345  }
346  else {
347  BLI_snprintf(r_owner, sizeof(*r_owner) * FILELIST_DIRENTRY_OWNER_LEN, "%u", st->st_uid);
348  }
349 #endif
350 }
351 
358 void BLI_filelist_entry_datetime_to_string(const struct stat *st,
359  const int64_t ts,
360  const bool compact,
361  char r_time[FILELIST_DIRENTRY_TIME_LEN],
362  char r_date[FILELIST_DIRENTRY_DATE_LEN],
363  bool *r_is_today,
364  bool *r_is_yesterday)
365 {
366  int today_year = 0;
367  int today_yday = 0;
368  int yesterday_year = 0;
369  int yesterday_yday = 0;
370 
371  if (r_is_today || r_is_yesterday) {
372  /* `localtime()` has only one buffer so need to get data out before called again. */
373  const time_t ts_now = time(NULL);
374  struct tm *today = localtime(&ts_now);
375 
376  today_year = today->tm_year;
377  today_yday = today->tm_yday;
378  /* Handle a yesterday that spans a year */
379  today->tm_mday--;
380  mktime(today);
381  yesterday_year = today->tm_year;
382  yesterday_yday = today->tm_yday;
383 
384  if (r_is_today) {
385  *r_is_today = false;
386  }
387  if (r_is_yesterday) {
388  *r_is_yesterday = false;
389  }
390  }
391 
392  const time_t ts_mtime = ts;
393  const struct tm *tm = localtime(st ? &st->st_mtime : &ts_mtime);
394  const time_t zero = 0;
395 
396  /* Prevent impossible dates in windows. */
397  if (tm == NULL) {
398  tm = localtime(&zero);
399  }
400 
401  if (r_time) {
402  strftime(r_time, sizeof(*r_time) * FILELIST_DIRENTRY_TIME_LEN, "%H:%M", tm);
403  }
404 
405  if (r_date) {
406  strftime(r_date,
407  sizeof(*r_date) * FILELIST_DIRENTRY_DATE_LEN,
408  compact ? "%d/%m/%y" : "%d %b %Y",
409  tm);
410  }
411 
412  if (r_is_today && (tm->tm_year == today_year) && (tm->tm_yday == today_yday)) {
413  *r_is_today = true;
414  }
415  else if (r_is_yesterday && (tm->tm_year == yesterday_year) && (tm->tm_yday == yesterday_yday)) {
416  *r_is_yesterday = true;
417  }
418 }
419 
423 void BLI_filelist_entry_duplicate(struct direntry *dst, const struct direntry *src)
424 {
425  *dst = *src;
426  if (dst->relname) {
427  dst->relname = MEM_dupallocN(src->relname);
428  }
429  if (dst->path) {
430  dst->path = MEM_dupallocN(src->path);
431  }
432 }
433 
437 void BLI_filelist_duplicate(struct direntry **dest_filelist,
438  struct direntry *const src_filelist,
439  const unsigned int nrentries)
440 {
441  unsigned int i;
442 
443  *dest_filelist = MEM_mallocN(sizeof(**dest_filelist) * (size_t)(nrentries), __func__);
444  for (i = 0; i < nrentries; i++) {
445  struct direntry *const src = &src_filelist[i];
446  struct direntry *dst = &(*dest_filelist)[i];
448  }
449 }
450 
455 {
456  if (entry->relname) {
457  MEM_freeN((void *)entry->relname);
458  }
459  if (entry->path) {
460  MEM_freeN((void *)entry->path);
461  }
462 }
463 
467 void BLI_filelist_free(struct direntry *filelist, const unsigned int nrentries)
468 {
469  unsigned int i;
470  for (i = 0; i < nrentries; i++) {
471  BLI_filelist_entry_free(&filelist[i]);
472  }
473 
474  if (filelist != NULL) {
475  MEM_freeN(filelist);
476  }
477 }
void BLI_filelist_entry_size_to_string(const struct stat *st, const uint64_t sz, const bool UNUSED(compact), char r_size[FILELIST_DIRENTRY_SIZE_LEN])
Definition: BLI_filelist.c:262
static void bli_builddir(struct BuildDirCtx *dir_ctx, const char *dirname)
Definition: BLI_filelist.c:121
void BLI_filelist_entry_datetime_to_string(const struct stat *st, const int64_t ts, const bool compact, char r_time[FILELIST_DIRENTRY_TIME_LEN], char r_date[FILELIST_DIRENTRY_DATE_LEN], bool *r_is_today, bool *r_is_yesterday)
Definition: BLI_filelist.c:358
void BLI_filelist_entry_mode_to_string(const struct stat *st, const bool UNUSED(compact), char r_mode1[FILELIST_DIRENTRY_MODE_LEN], char r_mode2[FILELIST_DIRENTRY_MODE_LEN], char r_mode3[FILELIST_DIRENTRY_MODE_LEN])
Definition: BLI_filelist.c:284
void BLI_filelist_free(struct direntry *filelist, const unsigned int nrentries)
Definition: BLI_filelist.c:467
unsigned int BLI_filelist_dir_contents(const char *dirname, struct direntry **r_filelist)
Definition: BLI_filelist.c:238
void BLI_filelist_entry_free(struct direntry *entry)
Definition: BLI_filelist.c:454
void BLI_filelist_entry_duplicate(struct direntry *dst, const struct direntry *src)
Definition: BLI_filelist.c:423
void BLI_filelist_entry_owner_to_string(const struct stat *st, const bool UNUSED(compact), char r_owner[FILELIST_DIRENTRY_OWNER_LEN])
Definition: BLI_filelist.c:334
void BLI_filelist_duplicate(struct direntry **dest_filelist, struct direntry *const src_filelist, const unsigned int nrentries)
Definition: BLI_filelist.c:437
static int bli_compare(struct direntry *entry1, struct direntry *entry2)
Definition: BLI_filelist.c:61
File and directory operations.
int BLI_stat(const char *path, BLI_stat_t *buffer) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
int BLI_access(const char *filename, int mode) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition: fileops.c:1024
#define PATH_MAX
Definition: BLI_fileops.h:44
Some types for dealing with directories.
#define FILELIST_DIRENTRY_SIZE_LEN
#define FILELIST_DIRENTRY_MODE_LEN
#define FILELIST_DIRENTRY_OWNER_LEN
#define FILELIST_DIRENTRY_DATE_LEN
#define FILELIST_DIRENTRY_TIME_LEN
void BLI_addhead(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:87
void BLI_freelist(struct ListBase *listbase) ATTR_NONNULL(1)
Definition: listbase.c:530
#define FILENAME_IS_CURRENT(_n)
void BLI_join_dirfile(char *__restrict dst, const size_t maxlen, const char *__restrict dir, const char *__restrict file) ATTR_NONNULL()
Definition: path_util.c:1737
#define FILENAME_IS_CURRPAR(_n)
#define FILENAME_CURRENT
#define FILENAME_PARENT
bool BLI_path_parent_dir(char *path) ATTR_NONNULL()
Definition: path_util.c:708
#define FILE_MAXDIR
#define FILENAME_IS_PARENT(_n)
void BLI_str_format_byte_unit(char dst[15], long long int bytes, const bool base_10) ATTR_NONNULL()
Definition: string.c:1206
int BLI_strcasecmp_natural(const char *s1, const char *s2) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition: string.c:766
char * BLI_strdup(const char *str) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL() ATTR_MALLOC
Definition: string.c:70
char * BLI_strdupcat(const char *__restrict str1, const char *__restrict str2) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL() ATTR_MALLOC
Definition: string.c:81
size_t BLI_snprintf(char *__restrict dst, size_t maxncpy, const char *__restrict format,...) ATTR_NONNULL(1
char * BLI_strncpy(char *__restrict dst, const char *__restrict src, const size_t maxncpy) ATTR_NONNULL()
Definition: string.c:108
#define UNUSED(x)
Compatibility-like things for windows.
struct __dirstream DIR
Definition: BLI_winstuff.h:100
int closedir(DIR *dp)
#define S_ISDIR(x)
Definition: BLI_winstuff.h:64
const char * dirname(char *path)
#define S_ISREG(x)
Definition: BLI_winstuff.h:61
struct dirent * readdir(DIR *dp)
DIR * opendir(const char *path)
typedef double(DMatrix)[4][4]
These structs are the foundation for all linked lists in the library system.
Read Guarded memory(de)allocation.
#define MEM_reallocN(vmemh, len)
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition: btDbvt.cpp:52
FILE * file
double time
static char ** types
Definition: makesdna.c:164
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:41
void *(* MEM_dupallocN)(const void *vmemh)
Definition: mallocn.c:42
void *(* MEM_mallocN)(size_t len, const char *str)
Definition: mallocn.c:47
__int64 int64_t
Definition: stdint.h:92
unsigned __int64 uint64_t
Definition: stdint.h:93
struct direntry * files
Definition: BLI_filelist.c:114
void * first
Definition: DNA_listBase.h:47
char * d_name
Definition: BLI_winstuff.h:96
const char * relname
const char * path