Changeset View
Changeset View
Standalone View
Standalone View
source/blender/blenlib/intern/BLI_filelist.c
| Show First 20 Lines • Show All 176 Lines • ▼ Show 20 Lines | if (newnum) { | ||||
| BLI_join_dirfile(fullname, sizeof(fullname), dirname, dlink->name); | BLI_join_dirfile(fullname, sizeof(fullname), dirname, dlink->name); | ||||
| if (BLI_stat(fullname, &file->s) != -1) { | if (BLI_stat(fullname, &file->s) != -1) { | ||||
| file->type = file->s.st_mode; | file->type = file->s.st_mode; | ||||
| } | } | ||||
| else if (FILENAME_IS_CURRPAR(file->relname)) { | else if (FILENAME_IS_CURRPAR(file->relname)) { | ||||
| /* Hack around for UNC paths on windows - does not support stat on '\\SERVER\foo\..', sigh... */ | /* Hack around for UNC paths on windows - does not support stat on '\\SERVER\foo\..', sigh... */ | ||||
| file->type |= S_IFDIR; | file->type |= S_IFDIR; | ||||
| } | } | ||||
| file->flags = 0; | |||||
| dir_ctx->nrfiles++; | dir_ctx->nrfiles++; | ||||
| file++; | file++; | ||||
| dlink = dlink->next; | dlink = dlink->next; | ||||
| } | } | ||||
| } | } | ||||
| else { | else { | ||||
| printf("Couldn't get memory for dir\n"); | printf("Couldn't get memory for dir\n"); | ||||
| exit(1); | exit(1); | ||||
| Show All 11 Lines | if ((dir = opendir(dirname)) != NULL) { | ||||
| closedir(dir); | closedir(dir); | ||||
| } | } | ||||
| else { | else { | ||||
| printf("%s non-existent directory\n", dirname); | printf("%s non-existent directory\n", dirname); | ||||
| } | } | ||||
| } | } | ||||
| /** | /** | ||||
| * Fills in the "mode[123]", "size" and "string" fields in the elements of the files | * Scans the contents of the directory named *dirname, and allocates and fills in an | ||||
| * array with descriptive details about each item. "string" will have a format similar to "ls -l". | * array of entries describing them in *filelist. | ||||
| * | |||||
| * \return The length of filelist array. | |||||
| */ | */ | ||||
| static void bli_adddirstrings(struct BuildDirCtx *dir_ctx) | unsigned int BLI_filelist_dir_contents(const char *dirname, struct direntry **r_filelist) | ||||
campbellbarton: can call `r_filelist` | |||||
| { | |||||
| struct BuildDirCtx dir_ctx; | |||||
| dir_ctx.nrfiles = 0; | |||||
| dir_ctx.files = NULL; | |||||
| bli_builddir(&dir_ctx, dirname); | |||||
| if (dir_ctx.files) { | |||||
| *r_filelist = dir_ctx.files; | |||||
| } | |||||
| else { | |||||
| // keep blender happy. Blender stores this in a variable | |||||
| // where 0 has special meaning..... | |||||
| *r_filelist = MEM_mallocN(sizeof(**r_filelist), __func__); | |||||
| } | |||||
| return dir_ctx.nrfiles; | |||||
| } | |||||
| /** | |||||
| * Convert given entry's size into human-readable strings. | |||||
| * | |||||
| */ | |||||
| void BLI_filelist_entry_size_to_string( | |||||
| const struct stat *st, const uint64_t sz, const bool compact, char r_size[FILELIST_DIRENTRY_SIZE_LEN]) | |||||
| { | { | ||||
| const char *types[8] = {"---", "--x", "-w-", "-wx", "r--", "r-x", "rw-", "rwx"}; | |||||
| /* symbolic display, indexed by mode field value */ | |||||
| int num; | |||||
| double size; | double size; | ||||
| struct direntry *file; | const char *fmt; | ||||
| struct tm *tm; | const char *units[] = {"KiB", "MiB", "GiB", "TiB", NULL}; | ||||
| time_t zero = 0; | const char *units_compact[] = {"K", "M", "G", "T", NULL}; | ||||
| const char *unit = "B"; | |||||
| #ifndef WIN32 | /* | ||||
| int mode; | * Seems st_size is signed 32-bit value in *nix and Windows. This | ||||
| #endif | * will buy us some time until files get bigger than 4GB or until | ||||
| * everyone starts using __USE_FILE_OFFSET64 or equivalent. | |||||
| */ | |||||
Done Inline ActionsWhy not to support terabytes. With alembic files around that'd make files list easier to read. sergey: Why not to support terabytes. With alembic files around that'd make files list easier to read. | |||||
| size = (double)(st ? st->st_size : sz); | |||||
| if (size > 1024.0) { | |||||
| const char **u; | |||||
| for (u = compact ? units_compact : units, size /= 1024.0; size > 1024.0 && *(u + 1); u++, size /= 1024.0); | |||||
| fmt = size > 100.0 ? "%.0f %s" : (size > 10.0 ? "%.1f %s" : "%.2f %s"); | |||||
| unit = *u; | |||||
| } | |||||
| else { | |||||
| fmt = "%.0f %s"; | |||||
| } | |||||
| BLI_snprintf(r_size, sizeof(*r_size) * FILELIST_DIRENTRY_SIZE_LEN, fmt, size, unit); | |||||
| } | |||||
| for (num = 0, file = dir_ctx->files; num < dir_ctx->nrfiles; num++, file++) { | /** | ||||
| * Convert given entry's modes into human-readable strings. | |||||
| * | |||||
| */ | |||||
| 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]) | |||||
| { | |||||
| const char *types[8] = {"---", "--x", "-w-", "-wx", "r--", "r-x", "rw-", "rwx"}; | |||||
| /* Mode */ | |||||
| #ifdef WIN32 | #ifdef WIN32 | ||||
| BLI_strncpy(file->mode1, types[0], sizeof(file->mode1)); | BLI_strncpy(r_mode1, types[0], sizeof(*r_mode1) * FILELIST_DIRENTRY_MODE_LEN); | ||||
| BLI_strncpy(file->mode2, types[0], sizeof(file->mode2)); | BLI_strncpy(r_mode2, types[0], sizeof(*r_mode2) * FILELIST_DIRENTRY_MODE_LEN); | ||||
| BLI_strncpy(file->mode3, types[0], sizeof(file->mode3)); | BLI_strncpy(r_mode3, types[0], sizeof(*r_mode3) * FILELIST_DIRENTRY_MODE_LEN); | ||||
| #else | #else | ||||
| mode = file->s.st_mode; | const int mode = st->st_mode; | ||||
| BLI_strncpy(file->mode1, types[(mode & 0700) >> 6], sizeof(file->mode1)); | BLI_strncpy(r_mode1, types[(mode & 0700) >> 6], sizeof(*r_mode1) * FILELIST_DIRENTRY_MODE_LEN); | ||||
| BLI_strncpy(file->mode2, types[(mode & 0070) >> 3], sizeof(file->mode2)); | BLI_strncpy(r_mode2, types[(mode & 0070) >> 3], sizeof(*r_mode2) * FILELIST_DIRENTRY_MODE_LEN); | ||||
| BLI_strncpy(file->mode3, types[(mode & 0007)], sizeof(file->mode3)); | BLI_strncpy(r_mode3, types[(mode & 0007)], sizeof(*r_mode3) * FILELIST_DIRENTRY_MODE_LEN); | ||||
| if (((mode & S_ISGID) == S_ISGID) && (file->mode2[2] == '-')) file->mode2[2] = 'l'; | if (((mode & S_ISGID) == S_ISGID) && (r_mode2[2] == '-')) r_mode2[2] = 'l'; | ||||
| if (mode & (S_ISUID | S_ISGID)) { | if (mode & (S_ISUID | S_ISGID)) { | ||||
| if (file->mode1[2] == 'x') file->mode1[2] = 's'; | if (r_mode1[2] == 'x') r_mode1[2] = 's'; | ||||
| else file->mode1[2] = 'S'; | else r_mode1[2] = 'S'; | ||||
| if (file->mode2[2] == 'x') file->mode2[2] = 's'; | if (r_mode2[2] == 'x') r_mode2[2] = 's'; | ||||
| } | } | ||||
| if (mode & S_ISVTX) { | if (mode & S_ISVTX) { | ||||
| if (file->mode3[2] == 'x') file->mode3[2] = 't'; | if (r_mode3[2] == 'x') r_mode3[2] = 't'; | ||||
| else file->mode3[2] = 'T'; | else r_mode3[2] = 'T'; | ||||
| } | } | ||||
| #endif | #endif | ||||
| } | |||||
| /** | |||||
| /* User */ | * Convert given entry's owner into human-readable strings. | ||||
| * | |||||
| */ | |||||
| void BLI_filelist_entry_owner_to_string( | |||||
| const struct stat *st, const bool UNUSED(compact), char r_owner[FILELIST_DIRENTRY_OWNER_LEN]) | |||||
| { | |||||
| #ifdef WIN32 | #ifdef WIN32 | ||||
| strcpy(file->owner, "user"); | strcpy(r_owner, "unknown"); | ||||
| #else | #else | ||||
| { | struct passwd *pwuser = getpwuid(st->st_uid); | ||||
| struct passwd *pwuser; | |||||
| pwuser = getpwuid(file->s.st_uid); | |||||
| if (pwuser) { | if (pwuser) { | ||||
| BLI_strncpy(file->owner, pwuser->pw_name, sizeof(file->owner)); | BLI_strncpy(r_owner, pwuser->pw_name, sizeof(*r_owner) * FILELIST_DIRENTRY_OWNER_LEN); | ||||
| } | } | ||||
| else { | else { | ||||
| BLI_snprintf(file->owner, sizeof(file->owner), "%u", file->s.st_uid); | BLI_snprintf(r_owner, sizeof(*r_owner) * FILELIST_DIRENTRY_OWNER_LEN, "%u", st->st_uid); | ||||
| } | |||||
| } | } | ||||
| #endif | #endif | ||||
| } | |||||
| /** | |||||
| /* Time */ | * Convert given entry's time into human-readable strings. | ||||
| tm = localtime(&file->s.st_mtime); | |||||
| // prevent impossible dates in windows | |||||
| if (tm == NULL) tm = localtime(&zero); | |||||
| strftime(file->time, sizeof(file->time), "%H:%M", tm); | |||||
| strftime(file->date, sizeof(file->date), "%d-%b-%y", tm); | |||||
| /* Size */ | |||||
| /* | |||||
| * Seems st_size is signed 32-bit value in *nix and Windows. This | |||||
| * will buy us some time until files get bigger than 4GB or until | |||||
| * everyone starts using __USE_FILE_OFFSET64 or equivalent. | |||||
| */ | */ | ||||
| size = (double)file->s.st_size; | 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]) | |||||
| { | |||||
| const struct tm *tm = localtime(st ? &st->st_mtime : &ts); | |||||
| const time_t zero = 0; | |||||
| if (size > 1024.0 * 1024.0 * 1024.0 * 1024.0) { | /* Prevent impossible dates in windows. */ | ||||
| BLI_snprintf(file->size, sizeof(file->size), "%.1f TiB", size / (1024.0 * 1024.0 * 1024.0 * 1024.0)); | if (tm == NULL) { | ||||
| } | tm = localtime(&zero); | ||||
| else if (size > 1024.0 * 1024.0 * 1024.0) { | |||||
| BLI_snprintf(file->size, sizeof(file->size), "%.1f GiB", size / (1024.0 * 1024.0 * 1024.0)); | |||||
| } | |||||
| else if (size > 1024.0 * 1024.0) { | |||||
| BLI_snprintf(file->size, sizeof(file->size), "%.1f MiB", size / (1024.0 * 1024.0)); | |||||
| } | |||||
| else if (size > 1024.0) { | |||||
| BLI_snprintf(file->size, sizeof(file->size), "%.1f KiB", size / 1024.0); | |||||
| } | } | ||||
| else { | |||||
| BLI_snprintf(file->size, sizeof(file->size), "%d B", (int)size); | if (r_time) { | ||||
| strftime(r_time, sizeof(*r_time) * FILELIST_DIRENTRY_TIME_LEN, "%H:%M", tm); | |||||
| } | } | ||||
| if (r_date) { | |||||
| strftime(r_date, sizeof(*r_date) * FILELIST_DIRENTRY_DATE_LEN, compact ? "%d/%m/%y" : "%d-%b-%y", tm); | |||||
| } | } | ||||
| } | } | ||||
| /** | /** | ||||
| * Scans the contents of the directory named *dirname, and allocates and fills in an | * Deep-duplicate of a single direntry. | ||||
| * array of entries describing them in *filelist. | |||||
| * | * | ||||
| * \return The length of filelist array. | * \param dup_poin If given, called for each non-NULL direntry->poin. Otherwise, pointer is always simply copied over. | ||||
| */ | */ | ||||
| unsigned int BLI_filelist_dir_contents(const char *dirname, struct direntry **filelist) | void BLI_filelist_entry_duplicate(struct direntry *dst, const struct direntry *src) | ||||
| { | { | ||||
| struct BuildDirCtx dir_ctx; | *dst = *src; | ||||
| if (dst->relname) { | |||||
| dir_ctx.nrfiles = 0; | dst->relname = MEM_dupallocN(src->relname); | ||||
| dir_ctx.files = NULL; | |||||
| bli_builddir(&dir_ctx, dirname); | |||||
| bli_adddirstrings(&dir_ctx); | |||||
| if (dir_ctx.files) { | |||||
| *filelist = dir_ctx.files; | |||||
| } | } | ||||
| else { | if (dst->path) { | ||||
| // keep blender happy. Blender stores this in a variable | dst->path = MEM_dupallocN(src->path); | ||||
| // where 0 has special meaning..... | |||||
| *filelist = MEM_mallocN(sizeof(**filelist), __func__); | |||||
| } | } | ||||
| return dir_ctx.nrfiles; | |||||
| } | } | ||||
| /** | /** | ||||
| * Deep-duplicate of an array of direntries, including the array itself. | * Deep-duplicate of an array of direntries, including the array itself. | ||||
| * | * | ||||
| * \param dup_poin If given, called for each non-NULL direntry->poin. Otherwise, pointer is always simply copied over. | * \param dup_poin If given, called for each non-NULL direntry->poin. Otherwise, pointer is always simply copied over. | ||||
| */ | */ | ||||
| void BLI_filelist_duplicate( | void BLI_filelist_duplicate( | ||||
| struct direntry **dest_filelist, struct direntry *src_filelist, unsigned int nrentries, | struct direntry **dest_filelist, struct direntry * const src_filelist, const unsigned int nrentries) | ||||
| void *(*dup_poin)(void *)) | |||||
| { | { | ||||
| unsigned int i; | unsigned int i; | ||||
| *dest_filelist = MEM_mallocN(sizeof(**dest_filelist) * (size_t)(nrentries), __func__); | *dest_filelist = MEM_mallocN(sizeof(**dest_filelist) * (size_t)(nrentries), __func__); | ||||
| for (i = 0; i < nrentries; ++i) { | for (i = 0; i < nrentries; ++i) { | ||||
| struct direntry * const src = &src_filelist[i]; | struct direntry * const src = &src_filelist[i]; | ||||
| struct direntry *dest = &(*dest_filelist)[i]; | struct direntry *dst = &(*dest_filelist)[i]; | ||||
| *dest = *src; | BLI_filelist_entry_duplicate(dst, src); | ||||
| if (dest->image) { | |||||
| dest->image = IMB_dupImBuf(src->image); | |||||
| } | |||||
| if (dest->relname) { | |||||
| dest->relname = MEM_dupallocN(src->relname); | |||||
| } | } | ||||
| if (dest->path) { | |||||
| dest->path = MEM_dupallocN(src->path); | |||||
| } | } | ||||
| if (dest->poin && dup_poin) { | |||||
| dest->poin = dup_poin(src->poin); | /** | ||||
| * frees storage for a single direntry, not the direntry itself. | |||||
| */ | |||||
| void BLI_filelist_entry_free(struct direntry *entry) | |||||
| { | |||||
| if (entry->relname) { | |||||
| MEM_freeN(entry->relname); | |||||
| } | } | ||||
| if (entry->path) { | |||||
| MEM_freeN(entry->path); | |||||
| } | } | ||||
| } | } | ||||
| /** | /** | ||||
| * frees storage for an array of direntries, including the array itself. | * frees storage for an array of direntries, including the array itself. | ||||
| */ | */ | ||||
| void BLI_filelist_free(struct direntry *filelist, unsigned int nrentries, void (*free_poin)(void *)) | void BLI_filelist_free(struct direntry *filelist, const unsigned int nrentries) | ||||
| { | { | ||||
| unsigned int i; | unsigned int i; | ||||
| for (i = 0; i < nrentries; ++i) { | for (i = 0; i < nrentries; ++i) { | ||||
| struct direntry *entry = filelist + i; | BLI_filelist_entry_free(&filelist[i]); | ||||
| if (entry->image) { | |||||
| IMB_freeImBuf(entry->image); | |||||
| } | |||||
| if (entry->relname) | |||||
| MEM_freeN(entry->relname); | |||||
| if (entry->path) | |||||
| MEM_freeN(entry->path); | |||||
| if (entry->poin && free_poin) | |||||
| free_poin(entry->poin); | |||||
| } | } | ||||
| if (filelist != NULL) { | if (filelist != NULL) { | ||||
| MEM_freeN(filelist); | MEM_freeN(filelist); | ||||
| } | } | ||||
| } | } | ||||
can call r_filelist