소스 검색

Added file tree walker.

Brucey 3 년 전
부모
커밋
c51b673c35
2개의 변경된 파일322개의 추가작업 그리고 2개의 파일을 삭제
  1. 101 2
      filesystem.mod/filesystem.bmx
  2. 221 0
      filesystem.mod/glue.c

+ 101 - 2
filesystem.mod/filesystem.bmx

@@ -6,12 +6,14 @@ bbdoc: System/File system
 End Rem
 Module BRL.FileSystem
 
-ModuleInfo "Version: 1.10"
+ModuleInfo "Version: 1.12"
 ModuleInfo "Author: Mark Sibly"
 ModuleInfo "License: zlib/libpng"
 ModuleInfo "Copyright: Blitz Research Ltd"
 ModuleInfo "Modserver: BRL"
 
+ModuleInfo "History: 1.12"
+ModuleInfo "History: Added file tree walker"
 ModuleInfo "History: 1.11"
 ModuleInfo "History: Added optional parameter timetype to FileTime"
 ModuleInfo "History: 1.10"
@@ -32,7 +34,9 @@ ModuleInfo "History: Added optional resurse parameter to CreateDir"
 Import Pub.StdC
 Import BRL.BankStream
 
-Const FILETYPE_NONE:Int=0,FILETYPE_FILE:Int=1,FILETYPE_DIR:Int=2
+Import "glue.c"
+
+Const FILETYPE_NONE:Int=0,FILETYPE_FILE:Int=1,FILETYPE_DIR:Int=2,FILETYPE_SYM:Int=3
 Const FILETIME_MODIFIED:Int=0,FILETIME_CREATED:Int=1
 
 Private
@@ -569,3 +573,98 @@ End Rem
 Function CloseFile( stream:TStream )
 	stream.Close
 End Function
+
+Rem
+bbdoc: Walks a file tree.
+End Rem
+Function WalkFileTree:Int(path:String, fileWalker:IFileWalker, options:EFileWalkOption = EFileWalkOption.None, maxDepth:Int = 0)
+	If MaxIO.ioInitialized Then
+		' TODO
+	Else
+		FixPath(path)
+		Return bmx_filesystem_walkfiletree(path, _walkfile, fileWalker, options, maxDepth)
+	End If
+End Function
+
+Rem
+bbdoc: An interface for file tree traversal.
+End rem
+Interface IFileWalker
+	Rem
+	bbdoc: Called once for each file/folder traversed.
+	about: Return EFileWalkResult.OK to continue the tree traversal, or EFileWalkResult.Terminate to exit early.
+
+	The contents of @attributes is only valid for the duration of the call.
+	End Rem
+	Method WalkFile:EFileWalkResult(attributes:SFileAttributes Var)
+End Interface
+
+Rem
+bbdoc: File attributes
+End rem
+Struct SFileAttributes
+?win32
+	Field StaticArray name:Short[8192]
+?not win32
+	Field StaticArray name:Byte[8192]
+?
+	Field fileType:short
+	Field depth:short
+	Rem
+	bbdoc: The size, in bytes, of the file.
+	End Rem
+	Field size:ULong
+	Field creationTime:Int
+	Field modifiedTime:Int
+
+	Rem
+	bbdoc: Returns the name of the file/directory.
+	End rem
+	Method GetName:String()
+?win32
+		Return String.FromWString(name)
+?not win32
+		Return String.FromUTF8String(name)
+?
+	End Method
+
+	Method IsRegularFile:Int()
+		Return fileType = FILETYPE_FILE
+	End Method
+
+	Method IsDirectory:Int()
+		Return fileType = FILETYPE_DIR
+	End Method
+
+	Method IsSymbolicLink:Int()
+		Return fileType = FILETYPE_SYM
+	End Method
+
+End Struct
+
+Rem
+bbdoc: 
+End rem
+Enum EFileWalkOption
+	None
+	FollowLinks
+End Enum
+
+Rem
+bbdoc: 
+End rem
+Enum EFileWalkResult
+	OK
+	Terminate
+	SkipSubtree
+	SkipSiblings
+End Enum
+
+Private
+Function _walkFile:EFileWalkResult(fileWalker:IFileWalker, attributes:SFileAttributes Var) { nomangle }
+	Return fileWalker.WalkFile(attributes)
+End Function
+
+Extern
+	Function bmx_filesystem_walkfiletree:Int(path:String, callback:EFileWalkResult(fileWalker:IFileWalker, attributes:SFileAttributes Var), walker:IFileWalker, options:EFileWalkOption, maxDepth:Int)
+End Extern

+ 221 - 0
filesystem.mod/glue.c

@@ -0,0 +1,221 @@
+/*
+ Copyright (c) 2022 Bruce A Henderson
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+    claim that you wrote the original software. If you use this software
+    in a product, an acknowledgment in the product documentation would be
+    appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+    misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+*/
+#include <brl.mod/blitz.mod/blitz.h>
+
+#define WALKRESULT_OK 0
+#define WALKRESULT_TERMINATE 1
+#define WALKRESULT_SKIP_SUBTREE 2
+#define WALKRESULT_SKIP_SIBLINGS 3
+
+#define FILETYPE_FILE 1
+#define FILETYPE_DIR 2
+#define FILETYPE_SYM 3
+
+#define FOLLOW_LINKS 1
+
+#if _WIN32
+
+#define WINDOWS_TICK 10000000
+#define SEC_TO_UNIX_EPOCH 11644473600LL
+
+struct SFileAttributes {
+	BBChar name[8192];
+    short fileType;
+	short depth;
+	BBUInt64 size;
+	int creationTime;
+	int modifiedTime;
+};
+
+extern int brl_filesystem__walkFile(BBObject * fileWalker, struct SFileAttributes * attributes);
+
+typedef int (*WalkFile)(BBObject * walker, struct SFileAttributes * attributes);
+
+int bmx_filesystem_walkfilerecurse(BBObject * walker, BBChar * dir, int depth, int maxDepth, int options) {
+
+    int res = WALKRESULT_OK;
+
+    WIN32_FIND_DATAW data;
+    HANDLE hnd = INVALID_HANDLE_VALUE;
+
+    struct SFileAttributes attributes;
+
+    BBChar p[8192];
+    _snwprintf(p, 8192, L"%s\\*", dir);
+
+    hnd = FindFirstFileW(p, &data);
+
+    if (hnd == INVALID_HANDLE_VALUE) {
+        return res;
+    }
+
+    do {
+        // skip . and ..
+        if (data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
+            if (wcscmp(data.cFileName, L".") == 0 || wcscmp(data.cFileName, L"..") == 0) {
+                continue;
+            }
+        }
+
+        BBChar fullpath[8192];
+        _snwprintf(fullpath, 8192, L"%s/%s", dir, data.cFileName);
+
+        memcpy(attributes.name, fullpath, 8192 * 2);
+        attributes.size = data.nFileSizeLow + (BBUInt64)data.nFileSizeHigh * 0xFFFFFFFFULL;
+        attributes.creationTime = (int)((((BBInt64)(data.ftCreationTime.dwHighDateTime)<<32) | (BBInt64)(data.ftCreationTime.dwLowDateTime)) / WINDOWS_TICK - SEC_TO_UNIX_EPOCH) / 1000;
+        attributes.modifiedTime = (int)((((BBInt64)(data.ftLastWriteTime.dwHighDateTime)<<32) | (BBInt64)(data.ftLastWriteTime.dwLowDateTime)) / WINDOWS_TICK - SEC_TO_UNIX_EPOCH) / 1000;
+
+        if (data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
+            attributes.fileType = FILETYPE_DIR;
+        } else if (data.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) {
+            attributes.fileType = FILETYPE_SYM;
+        } else {
+            attributes.fileType = FILETYPE_FILE;
+        }
+
+        res = brl_filesystem__walkFile(walker, &attributes);
+
+        if (res == WALKRESULT_TERMINATE) {
+            break;
+        }
+
+        if (data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
+            if (maxDepth && maxDepth < depth + 1) {
+                continue;
+            }
+
+            if (options != FOLLOW_LINKS && (data.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)) {
+                continue;
+            }
+
+            res = bmx_filesystem_walkfilerecurse(walker, fullpath, depth + 1, maxDepth, options);
+        }
+
+        if (res == WALKRESULT_TERMINATE) {
+            break;
+        }
+    } while (FindNextFileW(hnd, &data) != 0);
+
+    FindClose(hnd);
+
+    return res;
+}
+
+
+int bmx_filesystem_walkfiletree(BBString * path, WalkFile walkFile, BBObject * walker, int options, int maxDepth) {
+
+    BBChar p[8192];
+    _snwprintf(p, 8192, L"%s", bbStringToWString(path));
+
+    return bmx_filesystem_walkfilerecurse(walker, p, 0, maxDepth, options);
+}
+
+#else
+
+#include<sys/types.h>
+#include<sys/stat.h>
+#include<fts.h>
+
+struct SFileAttributes {
+	char name[8192];
+    short fileType;
+	short depth;
+	BBUInt64 size;
+	int creationTime;
+	int modifiedTime;
+};
+
+extern int brl_filesystem__walkFile(BBObject * fileWalker, struct SFileAttributes * attributes);
+
+typedef int (*WalkFile)(BBObject * walker, struct SFileAttributes * attributes);
+
+int bmx_filesystem_walkfiletree(BBString * path, WalkFile walkFile, BBObject * walker, int options, int maxDepth) {
+    FTSENT * child = NULL;
+    FTSENT * parent = NULL;
+
+    char * p = (char*)bbStringToUTF8String(path);
+
+    char * paths[2];
+    paths[0] = p;
+    paths[1] = NULL;
+
+    struct SFileAttributes attributes;
+
+    int opts = FTS_NOCHDIR;
+
+    if (options == FOLLOW_LINKS) {
+        opts += FTS_COMFOLLOW | FTS_LOGICAL;
+    }
+
+    FTS * fts = fts_open(paths, opts, NULL);
+
+    if (fts != NULL) {
+        while( (parent = fts_read(fts)) != NULL) {
+            int res = 0;
+
+            child = fts_children(fts,0);
+
+            while (child != NULL) {
+
+                if (maxDepth && maxDepth < child->fts_level) {
+                    break;
+                }
+
+                snprintf(attributes.name, 8192, "%s%s", child->fts_path, child->fts_name);
+                if (child->fts_statp != NULL) {
+                    attributes.size = child->fts_statp->st_size;
+                    attributes.creationTime = child->fts_statp->st_ctime;
+                    attributes.modifiedTime = child->fts_statp->st_mtime;
+                }
+
+                switch (child->fts_info) {
+                    case FTS_D:
+                        attributes.fileType = FILETYPE_DIR;
+                        break;
+                    case FTS_F:
+                        attributes.fileType = FILETYPE_FILE;
+                        break;
+                    case FTS_SL:
+                    case FTS_SLNONE:
+                        attributes.fileType = FILETYPE_SYM;
+                        break;
+                }
+
+                res = brl_filesystem__walkFile(walker, &attributes);
+
+                if (res == WALKRESULT_TERMINATE) {
+                    break;
+                }
+
+                child = child->fts_link;
+            }
+
+            if (res == WALKRESULT_TERMINATE) {
+                break;
+             }
+        }
+
+        fts_close(fts);
+    }
+    return 0;
+}
+
+
+#endif