diff --git a/pfs/.clang-format b/pfs/.clang-format
new file mode 100644
index 0000000..6fdf0c9
--- /dev/null
+++ b/pfs/.clang-format
@@ -0,0 +1,10 @@
+BasedOnStyle: Google
+AlignConsecutiveAssignments: true
+AllowShortFunctionsOnASingleLine: Empty
+AllowShortIfStatementsOnASingleLine: false
+ColumnLimit: 100
+DerivePointerAlignment: false
+IndentWidth: 4
+ObjCBlockIndentWidth: 4
+PointerAlignment: Left
+TabWidth: 4
diff --git a/pfs/.gitignore b/pfs/.gitignore
new file mode 100644
index 0000000..873989d
--- /dev/null
+++ b/pfs/.gitignore
@@ -0,0 +1 @@
+custom_makefile_variables
diff --git a/pfs/.gitmodules b/pfs/.gitmodules
new file mode 100644
index 0000000..e69de29
diff --git a/pfs/CHANGELOG.md b/pfs/CHANGELOG.md
new file mode 100644
index 0000000..892678d
--- /dev/null
+++ b/pfs/CHANGELOG.md
@@ -0,0 +1,19 @@
+# Changelog
+All notable changes to this project will be documented in this file.
+
+Please refer to README and design documentation under docs folder.
+WARNING: The code is not upto the design doc, with some of the
+pending work mentioned under Unreleased tag below, and
+also specified as TODO(For Implentation) in the design doc.
+
+## [Unreleased]
+- To support additional flags like volume-id and allow-reuse in manifest.
+- To support json encoding of volume-meta-data.
+- Add support to check if filename, is a valid UTF-8 string.
+- Directory-name confidentiality.
+
+## [0.1] - 2019-07-30
+### Added
+- Initial version. Maximum length of filenames for files that require
+protection is 180 bytes.
+
diff --git a/pfs/LICENSE b/pfs/LICENSE
new file mode 100644
index 0000000..0d9c8e6
--- /dev/null
+++ b/pfs/LICENSE
@@ -0,0 +1,35 @@
+LICENSE->Graphene-Filesystem-Shield is released under BSD License
+(http://www.opensource.org/licenses/BSD-3-Clause)
+
+==================COPYRIGHT INFO BELOW=============================
+
+Copyright (C) 2019 Intel Corporation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+ * Neither the name of Intel Corporation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+=================================================================
+
diff --git a/pfs/LICENSE.addendum b/pfs/LICENSE.addendum
new file mode 100644
index 0000000..f704e1b
--- /dev/null
+++ b/pfs/LICENSE.addendum
@@ -0,0 +1,8 @@
+Graphene-Filesystem-shield(GFS) is licensed under BSD.
+
+GFS also uses the following sources (and licenses):
+
+Sources from Intel's SGX SDK(in pfs_proxy folder) - BSD
+Patched sources for SGX SDK's protected-fs library - BSD
+Base64 encoding/decoding - BSD
+
diff --git a/pfs/Makefile b/pfs/Makefile
new file mode 100644
index 0000000..048ce58
--- /dev/null
+++ b/pfs/Makefile
@@ -0,0 +1,149 @@
+#To enable verbose mode in GCC
+#CXXFLAGS +=-v
+#To enable which headers it includes
+#CXXFLAGS +=-H
+
+CFLAGS_ASSEMBLY =-DPIC -DSHARED -fPIC -DASSEMBLER -Wa,--noexecstack -x assembler-with-cpp -DIN_ENCLAVE
+
+#Note: as part of build_deps.sh script, this libpfs_sdk.a, should already be built.
+PATH_TO_PFS_SDK_LIB=./pfs_sdk/
+
+DEPS_GRAPHENE=./deps/graphene
+DEPS_MBEDTLS=./deps/mbedtls
+DEPS_LINUX_SGX=./deps/linux-sgx
+
+#Note:
+#By default build script, sets up graphene in this path-> ./deps/graphene
+# Path variable DEPS_GRAPHENE can be updated(if needed),
+#in a file->custom_makefile_variables,
+# so that library(/libfileops_interceptor.so) will get
+#copied to user's graphene repo's Runtime directory path.
+# Add rule below in file->custom_makefile_variables, if path needs to be updated.
+#DEPS_GRAPHENE=/path_to_graphene_repo_directory_path/
+-include ./custom_makefile_variables
+
+$(info DEPS_GRAPHENE is $(DEPS_GRAPHENE))
+
+PATH_TO_GPFS_ROOT=./
+PATH_TO_PROTFS_PROXY=$(PATH_TO_GPFS_ROOT)/pfs_proxy
+PATH_TO_GPFS_PRELOAD=$(PATH_TO_GPFS_ROOT)/ld_preload_lib
+PROTFS_PROXY_OBJ_DIR=$(PATH_TO_GPFS_ROOT)/pfs_proxy/obj
+SGX_PROXY_INC=$(PATH_TO_PROTFS_PROXY)/sgx_proxy/inc
+SGX_PROXY_SRC=$(PATH_TO_PROTFS_PROXY)/sgx_proxy/src
+
+SDK_PROTECTFS=$(PATH_TO_GPFS_ROOT)/pfs_sdk/sdk/protected_fs
+
+#Related to linux_sgx
+EPID_SDK=$(DEPS_LINUX_SGX)/external/epid-sdk-3.0.0
+
+SGX_SDK_INCLUDES += -I$(DEPS_LINUX_SGX)/common/inc/internal \
+ -I$(EPID_SDK) -I$(DEPS_LINUX_SGX)/common/inc \
+ -I/opt/intel/sgxsdk/include \
+ -I$(DEPS_LINUX_SGX)//sdk/trts/ \
+ -I$(DEPS_LINUX_SGX)//sdk/trts/linux
+
+CXXFLAGS += -fPIC -Wall -std=gnu++11 \
+ -I$(SDK_PROTECTFS)/sgx_uprotected_fs/ \
+ -I$(SDK_PROTECTFS)/sgx_tprotected_fs/ \
+ -I$(PATH_TO_PROTFS_PROXY) \
+ -I$(PATH_TO_GPFS_PRELOAD) \
+ -I$(SGX_PROXY_INC)
+
+CXXFLAGS += $(SGX_SDK_INCLUDES)
+
+#Related to mbedtls
+MBEDTLS_INC=$(DEPS_MBEDTLS)/include
+MBEDTLS_SRC=$(DEPS_MBEDTLS)/library
+
+CXXFLAGS += -I$(MBEDTLS_INC)
+
+#CFLAGSERRORS=-Wall -Wextra -Wwrite-strings -Wlogical-op -Wshadow -Werror
+#Note: Enable Werror to get rid of warnings...
+CFLAGSERRORS=-Wall -Wextra -Wwrite-strings -Wlogical-op -Wshadow
+CXXFLAGS += $(CFLAGSERRORS)# -DDEBUG -DDYNAMIC_RSA
+
+CFLAGS := $(filter-out -std=gnu++11,$(CXXFLAGS))
+
+CFLAGS += -std=gnu99
+
+$(info CXXFLAGS is $(CXXFLAGS))
+$(info CFLAGS is $(CFLAGS))
+$(info PROTFS_PROXY_OBJ_DIR is $(PROTFS_PROXY_OBJ_DIR))
+$(info CXX is $(CXX))
+$(info CC is $(CC))
+
+#Using makefile's implicit rules to compile *.c files into *.o object files, using CFLAGS.
+#https://www.gnu.org/software/make/manual/html_node/Implicit-Variables.html
+MBEDTLS_CRYPTO_OBJS := $(MBEDTLS_SRC)/gcm.o $(MBEDTLS_SRC)/aes.o $(MBEDTLS_SRC)/cmac.o \
+ $(MBEDTLS_SRC)/cipher.o $(MBEDTLS_SRC)/cipher_wrap.o $(MBEDTLS_SRC)/aesni.o \
+ $(MBEDTLS_SRC)/ccm.o $(MBEDTLS_SRC)/sha256.o $(MBEDTLS_SRC)/md.o \
+ $(MBEDTLS_SRC)/md_wrap.o $(MBEDTLS_SRC)/md5.o $(MBEDTLS_SRC)/sha1.o \
+ $(MBEDTLS_SRC)/ripemd160.o $(MBEDTLS_SRC)/sha512.o $(MBEDTLS_SRC)/platform_util.o
+
+$(MBEDTLS_SRC)/libmbedtls_crypto.a: $(MBEDTLS_CRYPTO_OBJS)
+ $(AR) rcs $@ $^
+
+PROTFS_SGX_PROXY_SRC_FILES := $(wildcard $(SGX_PROXY_SRC)/*.cpp)
+PROTFS_SGX_PROXY_OBJ_FILES := $(patsubst $(SGX_PROXY_SRC)/%.cpp,$(PROTFS_PROXY_OBJ_DIR)/%.o,$(PROTFS_SGX_PROXY_SRC_FILES))
+
+$(PROTFS_PROXY_OBJ_DIR)/%.o: $(SGX_PROXY_SRC)/%.cpp
+ mkdir -p $(PROTFS_PROXY_OBJ_DIR)
+ g++ -c $(CXXFLAGS) $< -o $@
+
+PROTFS_SRC_FILES := $(wildcard $(PATH_TO_PROTFS_PROXY)/*.cpp)
+PROTFS_OBJ_FILES := $(patsubst $(PATH_TO_PROTFS_PROXY)/%.cpp,$(PROTFS_PROXY_OBJ_DIR)/%.o,$(PROTFS_SRC_FILES))
+
+$(PROTFS_PROXY_OBJ_DIR)/%.o: $(PATH_TO_PROTFS_PROXY)/%.cpp
+ g++ -c $(CXXFLAGS) $< -o $@
+
+PROTFS_ASSEMBLY_SRC_FILES := $(wildcard $(SGX_PROXY_SRC)/*.S)
+PROTFS_ASSEMBLY_OBJ_FILES := $(patsubst $(SGX_PROXY_SRC)/%.S,$(PROTFS_PROXY_OBJ_DIR)/%.o,$(PROTFS_ASSEMBLY_SRC_FILES))
+
+CFLAGS_ASSEMBLY += $(SGX_SDK_INCLUDES)
+
+$(PROTFS_PROXY_OBJ_DIR)/%.o: $(SGX_PROXY_SRC)/%.S
+ gcc -c $(CFLAGS_ASSEMBLY) $^ -o $@
+
+$(PATH_TO_PROTFS_PROXY)/libpfs_proxy.a: $(PROTFS_SGX_PROXY_OBJ_FILES) \
+ $(PROTFS_OBJ_FILES) $(PROTFS_ASSEMBLY_OBJ_FILES) -ldl
+ $(AR) rcs $@ $^
+
+$(PATH_TO_PFS_SDK_LIB)/libpfs_sdk.a:
+ cd $(PATH_TO_PFS_SDK_LIB) && make -fMakefile_pfs_sdk all
+
+FILEOPS_INTERCEPTOR_FILES := $(wildcard $(PATH_TO_GPFS_PRELOAD)/*.c)
+$(info FILEOPS_INTERCEPTOR_FILES is $(FILEOPS_INTERCEPTOR_FILES))
+
+$(PATH_TO_GPFS_PRELOAD)/libfileops_interceptor.so : $(FILEOPS_INTERCEPTOR_FILES) $(PATH_TO_PROTFS_PROXY)/libpfs_proxy.a $(MBEDTLS_SRC)/libmbedtls_crypto.a $(PATH_TO_PFS_SDK_LIB)/libpfs_sdk.a
+ g++ -o $@ $^ -g -std=c++11 -shared -fPIC $(CXXFLAGS) -L$(PATH_TO_PROTFS_PROXY) -L$(MBEDTLS_SRC) -L$(PATH_TO_PFS_SDK_LIB) -lpfs_proxy -lpfs_sdk -lmbedtls_crypto -ldl
+ cp $@ $(DEPS_GRAPHENE)/Runtime
+
+README.html : README.md
+ pandoc --from markdown_github --to html --standalone $< --output $@
+
+clean:
+#Not cleaning external libraries(that we dont modify) under
+#/deps/ in build_deps.sh.
+ rm -rf ./ld_preload_lib/libfileops_interceptor.so
+ rm -rf ./pfs_proxy/libpfs_proxy.a
+ rm -rf $(MBEDTLS_SRC)/libmbedtls_crypto.a $(MBEDTLS_SRC)/*.o
+ rm -rf $(SDK_PROTECTFS)/obj;
+ cd $(PATH_TO_PFS_SDK_LIB) && make -fMakefile_pfs_sdk clean
+
+all: format $(PATH_TO_GPFS_PRELOAD)/libfileops_interceptor.so
+
+.PHONY: format
+format:
+ clang-format -i $(shell find . -path ./deps -prune -o \
+ -path ./pfs_sdk -prune -o \
+ \( -name '*.h' -o -name '*.cpp' -o -name '*.c' \) -print)
+ #clang-format -i $(shell find ./pfs_sdk/sdk/protected_fs \
+ # \( -name '*.h' -o -name '*.cpp' -o -name '*.c' \) -print)
+
+mrproper: clean
+ $(RM) -r deps/graphene deps/linux-sgx deps/linux-sgx-driver
+ $(RM) -r deps/mbedtls
+ rm -rf ./pfs_sdk/.git
+ rm -rf ./pfs_sdk/sdk
+
+#.PHONY = all mrproper
diff --git a/pfs/README.md b/pfs/README.md
new file mode 100644
index 0000000..d799e7f
--- /dev/null
+++ b/pfs/README.md
@@ -0,0 +1,255 @@
+**Protected-FileSystem(PFS) shield library:**
+
+These sources produce a library, that provides file-system shield to [Graphene](https://github.com/oscarlab/graphene), by incorporating file protection feature from
+Intel's [SGX-SDK's Protected-FS library](https://github.com/intel/linux-sgx/tree/master/sdk/protected_fs).
+For sake of brevity, this feature or library will hereon be referred to as PFS.
+
+**ASSUMPTION/PRE-REQUISTE:**
+* User of this PFS library, is expected to be familiar with [Graphene-SGX](https://github.com/oscarlab/graphene/wiki/Introduction-to-Intel-SGX-Support).
+* User uses this PFS library, with Intel SGX enabled in Graphene.
+* User is also expected to be familiar with building applications using Graphene.
+* This PFS library will reside as an optional plugin at the top-level directory in Graphene repo.
+* User has familiarity with Intel's [SGX feature sources](https://github.com/intel/linux-sgx)
+* User has familiarity with Intel [SGX SDK's Protect-FS feature](https://software.intel.com/en-us/articles/overview-of-intel-protected-file-system-library-using-software-guard-extensions)
+
+**DETAILED OVERVIEW:**
+Integrated [SGX SDK's Protected-FS](https://github.com/intel/linux-sgx/tree/master/sdk/protected_fs) library WITHOUT sgx-sdk dependencies, as a library that can be linked by unmodified
+applications in [Graphene](https://github.com/oscarlab/graphene)\
+*Note: Sgx-sdk dependencies for crypto, getting EREPORT, EGETKEY, have been substituted by taking some of the related
+code from SGX-SDK, and packaging as part of this PFS library*
+
+Overloaded library called as libfileops_interceptor.so(i.e PFS library), has been added,which can route the file-related C api calls to corresponding api in SGX-SDK's Protected-FS library\
+(OR) regular glibc's file-system api\
+*Graphene application’s manfiest file, specifies the path to directory where protected files reside.
*
+For "List of Filesystem apis handled (and the ones not handled) by library", please refer to section below in README:
+
+Using the overloaded library(libfileops_interceptor.so), we are able to transparently intercept file-system api calls
+from unmodified application, and provide cryptographic protection mechanism(using SGX-ProtectedFS library).
+
+Files to be protected are mounted on pre-defined directory-path specified in graphene application's manifest.
+With SGX-SDK's Protected-FS mentioned above we only get confidentiality and integrity for fileÂ’s content, and integrity for filename.
+
+Additionally, with PFS library, we are able to add security mechanism for filename confidentiality, filename integrity, file-path integrity and\
+binding of files to a volume, on top of existing filesystem protection software (i.e. SGX-SDK's Protected-FS sources).
+
+To summarise, PFS provides filesystem shield feature in graphene, so that it extends Graphene(a system which allows existing applications to run inside SGX), with transparent protection of file I/O.
+More specifically, it transparently intercepts all file I/O calls and, if the implied filename is below some pre-defined mount-points, cryptographically protects
+the corresponding operations while interacting with the untrusted filesystem
+
+For more details refer to [design document](docs/design.md).
+
+**List of directories and components added:**
+1. [docs](docs) folder has design document. **Note: Code is NOT fully upto the design document, CHANGELOG has pending features,
+and you can also refer to tag->"TODO(For Implementation)" specified in design doc for additional features yet-to-be-implemented.
**
+With PFS library, the features that have been implemented are: filename confidentiality, filename integrity, file-path integrity and binding of files to a volume,
+on top of existing filesystem protection software (i.e. SGX-SDK's Protected-FS).
+2. [ld_preload_lib](ld_preload_lib): Has sources to intercept and overload file-system apis, and route it to SGX-SDK's Protected-FS library or to C filesystem api. Also has sources to augment cryptographic mechanisms
+to add additional features as described in the design doc under docs directory.
+3. [pfs_sdk](pfs_sdk): Has a patch file that gets applied on SGX-SDK's Protected-FS library, to make it work within graphene, without sgx-sdk dependencies.
+4. [pfs_proxy](pfs_proxy): Has changes, to hook calls from SGX-SDK's Protected-FS library sources, to non-sgx-sdk apis.
+5. [apps/pfs_app](apps/pfs_app): Has sources for sample graphene application, that sets the following in the
+application's manifest(specifies path to proteced directory, sets the overloaded PFS library, sets the type of key to be used for file-protection), and uses PFS library\
+transparently as a file-system shield
+
+**Maximum length of filenames allowed for protected files:**
+Given that protected files' names are encrypted and then base64 encoded,
+we have a maximum limit of 180 bytes for the length of filename of a protected file.
+The [design document](docs/design.md), discusses about base64 encoding of filenames for protected files.
+
+**Setting parameters in Graphene application's manifest:**
+*Note: Refer to [README](apps/pfs/README.md) under [apps/pfs_app](apps/pfs_app) for details on how to set various parameters in application's manifest*
+* Briefly, application's manifest has fields to set the overloaded library(libfileops_interceptor.so),
+ directory-path where protected-files are mounted, and type of key(SGX sealing key or custom-key) is
+ used to protect the files.
+*Note: High-level steps for how to generate sealed_custom_key file and process it is mentioned below.*
+*Note: Although [design document](docs/design.md) specifies volume-id setting in manifest, this is currently not supported yet.*
+
+**Build steps:**
+1. Installing dependencies(under ./deps) for the build.
+./build_deps.sh
+Note: Above script->build_deps.sh will prompt user to install a version of Graphene,
+under ./deps. Installation of graphene can be skipped by the user, if user already has Graphene
+installed in a different directory path.
+
+2. Building the PFS library:
+If user has Graphene installed in a different directory path(default path is ./deps/graphene):
+i. Add a file->custom_makefile_variables, with path set to your graphene repo.
+ii. Add rule below in file->custom_makefile_variables, with the directory-path.
+iii. DEPS_GRAPHENE=/path_to_graphene_repo_directory_path/
+and then run the script below:
+./build_library.sh
+Above script will copy the library(libfileops_interceptor.so)
+into the Runtime directory of graphene.
+
+3. Building sample application at apps/pfs_app:
+cd apps/pfs_app
+User needs to update pfs_application's manifest file with the path of Graphene and other configuration parameters.
+For configuration setup, application build steps, and for details on how to set various parameters in application's manifest,
+refer to [README](apps/pfs_app/README.md) under [apps/pfs_app](apps/pfs_app)
+
+**Kernel Driver Dependencies:**
+1. Need to make sure that both SGX driver and graphene SGX driver are loaded to run graphene.
+2. [SGX Driver installation](https://github.com/intel/linux-sgx-driver) steps.
+3. [Graphene SGX Driver installation](https://github.com/oscarlab/graphene/wiki/SGX-Quick-Start) steps
+4. When you do lsmod | grep sgx, you would have to see the following drivers loaded:
+graphene_sgx
+isgx
+
+
+**Steps for how to generate sealed_custom_key file:**
+**Pre-requistes generate sealed_custom_key file:**
+Custom key can be generated on a SGX system(Factory system A) within trusted premises(like a factory-like enviornment).
+Custom key needs to sent via SGX remote attestation to the target SGX system(Target system B).
+Note: These are high-level steps:
+1. SGX enclave(Enclave A) running on system A needs to generate random custom key and
+send custom key to SGX enclave(Enclave B) on system B, through remote attestation.
+2. Once Enclave B(running on Target system B) receives the custom key via SGX remote attestation, it needs to
+invoke SGX sealing api, to seal the custom-key and output the sealed blob to file-system on Target system B.
+
+**Steps for how to process existing sealed_custom_key file:**
+**Pre-requisite: sealed-custom key, is generated and exists in filesystem as explained above.:**
+1. If PFS_USE_CUSTOM_KEY is set to 'yes' in application's manifest, this library(fops_interceptor.so), will expect a sealed_custom_key, in the current working directory\
+of the application.
+2. If present, it will unseal the blob, and save the custom-key in graphene application's memory(application runs as SGX enclave)
+3. [Design document](docs/design.md) descibes how custom file-content protection key and other keys are derived from this custom-key.
+3. So for any C filesystem api calls that application invokes like fopen/fread/fwrite and so on, custom file-content protection key(derived
+from custom-key) will be used to protect the contents of the files.
+
+**List of Filesystem apis handled (and the ones not handled) by library:**
+**Note: For non-protected files, ALL C filesystem apis are supported.**
+The list below for what is supported/not-supported, only applies
+to protected files.
+
+**List of C filesystem apis(returns or uses FILE *) supported by library:**
+**SUPPORTED: For the apis below, library will intercept and route it to SGX-ProtectedFS library api:**
+* fopen
+* fflush
+* fclose
+* fread
+* fwrite
+* fgetc
+* getc
+* fgets
+* fputc
+* putc
+* fputs
+* ungetc
+* ftell
+* ftello
+* fseek
+* fseeko
+* rewind
+* clearerr
+* ferror
+* feof
+* remove
+
+**C filesystem apis(file-descriptor based apis) NOT supported by library:**
+Note: Un-supported apis can still be used for files that do NOT need protection. For any calls to un-supported apis,
+if the path matches with the protected_directory specified in the manifest, then PFS library, will NOT allow those calls,
+and will return an error.
*
+
+**Apis that take file-descriptor are NOT supported. APIs that create new file-descriptor like
+open/openat/creat are NOT supported. Library will intercept and return error:**
+* open
+* openat
+* creat(and their 64-bit versions).
+
+*Since open/openat/creat are NOT supported for protected-files, any api that passes fd(file-descriptor) is NOT intercepted by the library.
+Since those system calls(using file-descriptor) will be for non-protected files, it will be directly handled by underlying C library
*
+
+****For the un-supported (returns or uses FILE *) apis below, library will intercept and return error gracefully.:****
+* freopen
+* truncate
+* setbuf
+* setbuffer
+* setlinebuf
+* setvbuf
+* vfscanf
+* vfprintf
+* fgetpos
+* fsetpos
+* fileno
+* fscanf
+* fprintf
+
+**File-rename apis NOT supported, intercepted by library, and returns error:**
+* rename
+* renameat
+
+**Wide-character FILE * apis, NOT supported, intercepted by library, and returns error:**
+* fwide
+* fgetwc
+* getwc
+* fgetws
+* fputwc
+* putwc
+* fputws
+* ungetwc
+* vfwscanf
+* vfwprintf
+* fwscanf
+* fwprintf
+
+**List of 64-bit Filesystem apis handled (and the ones not handled) by library:**
+Note: For 32-bit systems, C lib provides 64 bit versions of certain apis, mainly related
+to file-open/seek/tell to support LFS(Large-File-system) on 32-bit systems.
+The program should enable this conditional->_FILE_OFFSET_BITS == 64, to use 64-bit apis(and types)
+on 32-bit systems. On 64-bit systems, no such conditional is needed , by default apis(and types)
+are 64-bit compliant. For example, calling fseek on 64 bit-system is equivalent to calling fseek64 api.**
+****SUPPORTED: List of 64-bit C filesystem apis(returns or uses FILE *) supported by library:****
+* fopen64
+* ftello64
+* fseeko64
+
+**64-bit C filesystem apis(file-descriptor based apis) NOT supported by library. Library will intercept and return error::**
+* open64
+* openat64
+* creat64
+
+****For the 64-bit un-supported (returns or uses FILE *) apis below, library will intercept and return error gracefully.:****
+* freopen64
+* fgetpos64
+* fsetpos64
+
+
+**List of directory-system handled (and the ones not handled) by library:**
+**Note: For non-protected files, ALL C directory-system apis are supported.**
+The list below for what is supported/not-supported, only applies
+to directory-paths(where protected files reside), as set
+in application's manifest.
+
+**SUPPORTED: List of directory-system apis supported by library:**
+* opendir
+* closedir
+* readdir
+* readdir64
+* rewindir
+* seekdir
+* telldir
+
+**List of directory-system apis NOT-supported, intercepted by library, and returns error:**
+* readdir_r
+* readdir64_r
+* dirfd
+* scandir
+* scandir64
+* scandirat
+* scandirat64
+* nftw
+* nftw64
+
+**NO interception/handling for apis below. Since open/openat/creat are NOT supported for directory-paths
+where protected-files reside**
+System calls(using file-descriptor) will be for directory-paths to NON-protected files, and it will
+be directly handled by underlying C library.:
+* fdopendir
+* getdirentries
+* getdirentries64
+
+**NO interception/handling for apis below. Not feasible to
+intercept and handle these apis.:**
+* alphasort
+* alphasort64
+* versionsort
+* versionsort64
diff --git a/pfs/apps/pfs_app/Makefile b/pfs/apps/pfs_app/Makefile
new file mode 100644
index 0000000..a6c7d87
--- /dev/null
+++ b/pfs/apps/pfs_app/Makefile
@@ -0,0 +1,100 @@
+
+cxx_srcs = $(patsubst %.cpp,%.cpp,$(wildcard *.cpp))
+
+GRAPHENE_PATH = ../../deps/graphene
+SHIMDIR = $(GRAPHENE_PATH)/LibOS/shim/src
+
+$(info GRAPHENE_PATH is $(GRAPHENE_PATH))
+$(info SHIMDIR is $(SHIMDIR))
+
+#To enable verbose mode in GCC
+CXXFLAGS +=-v
+#To enable which headers it includes
+#CXXFLAGS +=-H
+
+PATH_TO_PFS_SDK_LIB=$(PATH_TO_PFS_ROOT)/pfs_sdk/
+
+#TODO: Needs to be updated as needed
+PATH_TO_PFS_ROOT=../../
+PATH_TO_PFS_PROXY=$(PATH_TO_PFS_ROOT)/pfs_proxy
+PATH_TO_PFS_PRELOAD=$(PATH_TO_PFS_ROOT)/ld_preload_lib
+PFS_PROXY_OBJ_DIR=$(PATH_TO_PFS_ROOT)/pfs_proxy/obj
+SGX_PROXY_INC=$(PATH_TO_PFS_PROXY)/sgx_proxy/inc
+SGX_PROXY_SRC=$(PATH_TO_PFS_PROXY)/sgx_proxy/src
+
+SDK_PROTECTFS=$(PATH_TO_PFS_ROOT)/pfs_sdk/sdk/protected_fs
+
+SGX_GIT=$(PATH_TO_PFS_ROOT)/deps/linux-sgx
+EPID_SDK=$(SGX_GIT)/external/epid-sdk-3.0.0
+
+MBEDTLS=$(PATH_TO_PFS_ROOT)/deps/mbedtls
+MBEDTLS_INC=$(MBEDTLS)/include
+MBEDTLS_SRC=$(MBEDTLS)/library
+
+SGX_SDK_INCLUDES += -I$(SGX_GIT)/common/inc/internal \
+ -I$(EPID_SDK) -I$(SGX_GIT)/common/inc \
+ -I/opt/intel/sgxsdk/include
+
+CXXFLAGS += -fPIC -Wall -std=gnu++11 \
+ -I$(SDK_PROTECTFS)/sgx_uprotected_fs/ \
+ -I$(SDK_PROTECTFS)/sgx_tprotected_fs/ \
+ -I$(PATH_TO_PFS_PROXY) \
+ -I$(PATH_TO_PFS_PRELOAD) \
+ -I$(SGX_PROXY_INC)
+
+CXXFLAGS += $(SGX_SDK_INCLUDES)
+
+CXXFLAGS += -I. -Ideps/local/include
+#CFLAGSERRORS=-Werror -Wall -Wextra -Wwrite-strings -Wlogical-op -Wshadow
+CFLAGSERRORS=-Wall -Wextra -Wwrite-strings -Wlogical-op -Wshadow
+CXXFLAGS += $(CFLAGSERRORS)# -DDEBUG -DDYNAMIC_RSA
+
+#Note: Below flags needed only to test
+#64 bit apis(explicitly like on 32-bit systems).
+#On 64-bit systems, this conditional NOT needed.
+#Enabling below conditional...replaces calls to 64-bit
+#equivalent apis..like readdir to readdir64.
+#CXXFLAGS += -D_FILE_OFFSET_BITS=64
+
+CFLAGS := $(filter-out -std=gnu++11,$(CXXFLAGS))
+
+CFLAGS += -std=gnu99
+
+
+CFLAGS += -I$(MBEDTLS_INC)
+
+$(info CXXFLAGS is $(CXXFLAGS))
+$(info CFLAGS is $(CFLAGS))
+$(info PFS_PROXY_OBJ_DIR is $(PFS_PROXY_OBJ_DIR))
+
+#For debugging symbols.
+CXXFLAGS +=-g
+
+CXXFLAGS += -I$(SHIMDIR)/../../../Pal/src/host/Linux-SGX/ \
+ -I$(SHIMDIR)/../../../Pal/include/pal \
+ -I$(MBEDTLS_INC)
+ #-I$(SHIMDIR)/../../../Pal/lib/crypto/mbedtls/mbedtls/
+
+$(info CXXFLAGS is $(CXXFLAGS))
+
+
+pfs_app:
+ $(info cxx_srcs is $(cxx_srcs))
+ g++ -o pfs_app $(cxx_srcs) $(CXXFLAGS) -L$(PATH_TO_PFS_PROXY) -L$(MBEDTLS_SRC) -L$(PATH_TO_PFS_SDK_LIB) -lpfs_proxy -lpfs_sdk -lmbedtls_crypto -ldl
+ $(GRAPHENE_PATH)/Pal/src/host/Linux-SGX/signer/pal-sgx-sign -libpal $(GRAPHENE_PATH)/Runtime/libpal-Linux-SGX.so -key $(GRAPHENE_PATH)/Pal/src/host/Linux-SGX/signer/enclave-key.pem -output $@.manifest.sgx -exec $@ -manifest pfs_app.manifest.template
+ $(GRAPHENE_PATH)/Pal/src/host/Linux-SGX/signer/pal-sgx-get-token -output $@.token -sig $@.sig
+
+#mbedtls-ssl-server : $(MBEDTLS_SSL_SERVER_SRC) ssl-server.manifest deps/graphene/Runtime/pal_loader
+# $(CC) $(MBEDTLS_SSL_SERVER_SRC) -o $@ $(CFLAGSERRORS) $(SSL_SERVER_INCLUDES) -Ldeps/local/lib/ $(MBEDTLS_SSL_SERVER_LIBS)
+# deps/graphene/Pal/src/host/Linux-SGX/signer/pal-sgx-sign -libpal deps/graphene/Runtime/libpal-Linux-SGX.so -key deps/graphene/Pal/src/host/Linux-SGX/signer/enclave-key.pem -output $@.manifest.sgx -#exec $@ -manifest ssl-server.manifest
+# deps/graphene/Pal/src/host/Linux-SGX/signer/pal-sgx-get-token -output $@.token -sig $@.sig
+
+
+.PHONY: format
+format:
+ clang-format -i $(shell find . \( -name '*.h' -o -name '*.cpp' -o -name '*.c' \) -print)
+
+all: pfs_app
+
+clean:
+ $(RM) pfs_app pfs_app.token pfs_app.sig pfs_app.manifest.sgx
diff --git a/pfs/apps/pfs_app/README.md b/pfs/apps/pfs_app/README.md
new file mode 100644
index 0000000..be091a4
--- /dev/null
+++ b/pfs/apps/pfs_app/README.md
@@ -0,0 +1,83 @@
+**Pre-requiste:**
+Please refer to README.md at the top-level directory, to get an overview on Protected-Filesystem(PFS) shield library,
+and the build and setup steps, before reading below.
+For sake of brevity, this feature or library will hereon be referred to as PFS.
+
+PFS library(libfileops_interceptor.so) will be used by pfs application, to transparently intercept filesystem I/O apis, and thereby
+provide filesystem shield, and internally invoke apis in file protection feature from
+Intel's [SGX-SDK's Protected-FS](https://github.com/intel/linux-sgx/tree/master/sdk/protected_fs) library.
+
+**SETUP PRIOR TO RUNNING THE PROTFS_APP:**
+**NOTE:** The application's manifest file(pfs_app.manifest.template), needs some modifications(as explained below), in order for it work as expected.
+
+* application's manifest should be set to point to the Runtime folder in graphene repo.
+For example, in the example manifest file, path is->../../deps/graphene/Runtime, it needs to be changed as per user's path to graphene repo.
+* User needs to setup physical directory path(on user's system) to a mount-point, so graphene can mount(i.e. map) the physical
+directory path to a virtual directory path in in its internal namespace.
+Update below in the application manifest file(user needs to change as per user's setup):
+Physical directory path is->/home/skris14/pfs_mount
+Virtual directory path is ->/pfs_dir
+* Setting the overloaded PFS library:
+*loader.env.LD_PRELOAD = libfileops_interceptor.so
*
+* Mapping the physical directory path to virtual directory path in manifest:
+Update below in the application manifest file(user needs to change as per user's setup):
+*fs.mount.pfs.type = chroot
+fs.mount.pfs.path = /pfs_dir
+fs.mount.pfs.uri = file:/home/skris14/pfs_mount
*
+* User needs to be setup the following directory structure under the physical directory path(like below):
+cd to mount_point, and then run below:
+mkdir -p test_dir secrets/sub_dir1 secrets/sub_dir2 non_secrets
+
+After creating above sub-directories, doing ls at mount-point, should list below:
+~/pfs_mount$ ls -ltr
+test_dir
+secrets
+non_secrets
+~/pfs_mount$ ls -ltr secrets/
+sub_dir2
+sub_dir1
+
+* Setting root of protected directory(PFS_MOUNT_POINT):
+**Note: PFS_MOUNT_POINT points to the top-level directory that can have protected files.**
+Update below in the application manifest file(user needs to change as per user's setup):
+loader.env.PFS_MOUNT_POINT = /pfs_dir/secrets
*
+Note that /pfs_dir is virtual directory-path. Physical directory-path has been mapped
+to this virtual path in graphene's namespace, as explained earlier.
+In this example, PFS_MOUNT_POINT happens to be a sub-directory of the physical directory that has been mounted
+and mapped to virtual directory path as per rules in graphene's manifest file.
+* User needs to allow access to files under a given directory:
+Update below in the application manifest file(user needs to change as per user's setup):
+*sgx.allowed_files.mount_path = file:/home/skris14/pfs_mount
*
+**Note: In this example, we have allowed access to files in the parent directory
+of PFS_MOUNT_POINT. Reason being this application accesses some of the non-protected directories using the virtual directory path.**
+
+* Setting file-protection key-type:
+Set PFS_USE_CUSTOM_KEY, in application's manifest, to indicate whether PFS will be using custom key or autokey(i.e sealing key)
+Update below in the application manifest file(user needs to change as per user's setup):
+*loader.env.PFS_USE_CUSTOM_KEY = no
*
+If PFS_USE_CUSTOM_KEY is set to 'no' in application's manifest, PFS, will use SGX sealing key for protecting files.
+Design doc under docs folder descibes how keys for filename encryption and other keys are derived from SGX sealing-key.
+If PFS_USE_CUSTOM_KEY is set to 'yes' in application's manifest, this library(fops_interceptor.so), will expect a sealed_custom_key, in the current working directory
+of the application.
+***Note: High-level steps for how to generate sealed_custom_key file and process it is mentioned in README under the top-level directory.*
***
+
+**BUILDING AND RUNNING THE APP:**
+1. Option1: If PFS is already built, and just to build app and run
+*./build_app.sh
+./run_app.sh
*
+2. Option2: To re-build PFS library, and then build app and run
+*./build_library_app_run.sh
*
+
+**PROTFS_APP DETAILS:**
+ 1. pfs_override_test(PATH_TO_PFS_TESTFILE) API:
+ Creates and/or updates a file. Note that it just calls file-system apis, like fopen, fread and so on,
+ but the overloaded PFS library(libfileops_interceptor.so), intercepts those calls, and depending on the path specified in the manifest,
+ it can either protect the file, by calling SGX SDK's protected-fs apis or route it to regular system call.
+ 2. protect_files(CLEAR_DIR_PATH, PROTECTED_DIR_PATH) API:
+ This API can be used to take existing files in clear(non-encrypted) and output protected files.
+ It expects path to directory that has clear files(CLEAR_DIR_PATH), and outputs protected files
+ to protected directory(PROTECTED_DIR_PATH, which should be same as sub-directory of PFS_MOUNT_POINT
+ in manifest).
+ Additionally if CLEAR_DIR_PATH has sub-directories, it can replicate the sub-directories in
+ PROTECTED_DIR_PATH. To summarise, it can recursively traverse the directory-tree under CLEAR_DIR_PATH
+ and create sub-directories(if needed) in PROTECTED_DIR_PATH and output protected files.
diff --git a/pfs/apps/pfs_app/build_app.sh b/pfs/apps/pfs_app/build_app.sh
new file mode 100755
index 0000000..29a8713
--- /dev/null
+++ b/pfs/apps/pfs_app/build_app.sh
@@ -0,0 +1,3 @@
+make clean
+
+make all
diff --git a/pfs/apps/pfs_app/build_library_app_run.sh b/pfs/apps/pfs_app/build_library_app_run.sh
new file mode 100755
index 0000000..98be86f
--- /dev/null
+++ b/pfs/apps/pfs_app/build_library_app_run.sh
@@ -0,0 +1 @@
+cd ../../; ./build_library.sh ; cd - ; make format; sudo ./build_app.sh; sudo ./run_app.sh
diff --git a/pfs/apps/pfs_app/pal_loader b/pfs/apps/pfs_app/pal_loader
new file mode 120000
index 0000000..f0a9d2e
--- /dev/null
+++ b/pfs/apps/pfs_app/pal_loader
@@ -0,0 +1 @@
+../../deps/graphene/Runtime/pal_loader
\ No newline at end of file
diff --git a/pfs/apps/pfs_app/perf_meas.cpp b/pfs/apps/pfs_app/perf_meas.cpp
new file mode 100644
index 0000000..d2ae629
--- /dev/null
+++ b/pfs/apps/pfs_app/perf_meas.cpp
@@ -0,0 +1,244 @@
+/*
+ * License: BSD 3-Clause "New" or "Revised" License
+ *
+ * Other web pages for this license
+ * http://www.opensource.org/licenses/BSD-3-Clause
+ *
+ * Copyright (C) 2019 Intel Corporation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+
+#include "perf_meas.h"
+
+#include
+#include
+
+#include "pfs_app.h"
+
+float perf_meas[MAX_APIS];
+// Note: Order of strings needs to match, with enum->apis_measured above.
+char apis_meas[MAX_APIS][255] = {"fopen", "fread", "fwrite", "fflush", "fseek", "ftell", "fclose"};
+
+uint8_t onek_buf[1024] = {1};
+uint8_t twok_buf[2048] = {2};
+uint8_t fourk_buf[4096] = {4};
+uint8_t eightk_buf[8192] = {8};
+
+struct perf_run runs[] = {{onek_buf, sizeof(onek_buf)},
+ {twok_buf, sizeof(twok_buf)},
+ {fourk_buf, sizeof(fourk_buf)},
+ {eightk_buf, sizeof(eightk_buf)}};
+
+void get_time(struct timeval* time) {
+ if (!time)
+ return;
+
+ gettimeofday(time, NULL);
+}
+
+void compute_duration(struct timeval* t1, struct timeval* t2, float* elapsed) {
+ if (!t1 || !t2 || !elapsed)
+ return;
+
+ *elapsed = t2->tv_sec - t1->tv_sec;
+ *elapsed += (t2->tv_usec - t1->tv_usec) / 1e6;
+}
+
+void get_time_and_compute_duration(struct timeval* t1, struct timeval* t2, float* elapsed) {
+ if (!t1 || !t2 || !elapsed)
+ return;
+
+ get_time(t2);
+
+ compute_duration(t1, t2, elapsed);
+}
+
+void print_perf_meas(size_t buf_len, bool pfs_file) {
+ int i = 0;
+
+ printf("\nperf meas for file_type=%s, buf_size=%lu\n",
+ ((pfs_file) ? "PFS_FILE" : "NON_PFS_FILE"), buf_len);
+
+ for (i = 0; i < MAX_APIS; i++) {
+ printf("%s, %f\n", apis_meas[i], perf_meas[i]);
+ }
+}
+
+int pfs_perf_meas_test(const char* path_to_file, uint8_t* input_buf, size_t buf_len) {
+ FILE* sfp = NULL;
+ size_t buffer_len = 0;
+ int32_t ret_val = 0;
+ struct timeval t1, t2;
+ float elapsed;
+
+ if (!path_to_file || !input_buf || (buf_len == 0)) {
+ printf("\nDEBUG: invalid params to %s", __func__);
+ return -1;
+ }
+
+ printf("\nsizeof(path)=%lu, file-name=%s", strlen(path_to_file), path_to_file);
+
+ get_time(&t1);
+ sfp = fopen((const char*)path_to_file, "rb+");
+
+ if (sfp != NULL)
+ get_time_and_compute_duration(&t1, &t2, &elapsed);
+ perf_meas[FOPEN] = elapsed;
+
+ printf("\nDEBUG, %s:%d, after fopen to check if file exists, sfp=%p\n", __func__, __LINE__,
+ sfp);
+
+ if (sfp == NULL) {
+ printf("\nDEBUG, creating new testfile in wb+ mode \n");
+
+ get_time(&t1);
+ sfp = fopen((const char*)path_to_file, "w+b");
+ get_time_and_compute_duration(&t1, &t2, &elapsed);
+ perf_meas[FOPEN] = elapsed;
+ } else {
+ fclose(sfp);
+ printf("\nDEBUG, opening existing file-%s in ab+ mode\n", path_to_file);
+
+ sfp = fopen((const char*)path_to_file, "a+b");
+ }
+
+ printf("\nDEBUG, %s:%d, after open, sfp=%p\n", __func__, __LINE__, sfp);
+
+ if (!sfp) {
+ printf("\nDEBUG, %s:%d, error sfp=%p is NULL\n", __func__, __LINE__, sfp);
+ return -1;
+ }
+
+ get_time(&t1);
+ buffer_len = fwrite(input_buf, sizeof(uint8_t), buf_len, sfp);
+ get_time_and_compute_duration(&t1, &t2, &elapsed);
+ perf_meas[FWRITE] = elapsed;
+ printf("DEBUG, after fwrite, buffer_len = %d\n", (int)buffer_len);
+
+ /*Note: skipping fflush here, and trying to measure..potential
+ flush from cache..during fclose
+ get_time(&t1);
+ ret_val = fflush(sfp);
+ get_time_and_compute_duration(&t1, &t2, &elapsed);
+ perf_meas[FFLUSH] = elapsed;
+ printf("DEBUG, after fflush, ret_val = %d\n", (int)ret_val);
+ */
+
+ ret_val = ferror(sfp);
+ printf("DEBUG, after ferror, ret_val = %d\n", (int)ret_val);
+
+ memset(input_buf, 0, buf_len);
+
+ get_time(&t1);
+ ret_val = fseek(sfp, 0L, SEEK_SET);
+ get_time_and_compute_duration(&t1, &t2, &elapsed);
+ perf_meas[FSEEK] = elapsed;
+ printf("DEBUG, after fseek, ret = %d\n", (int)ret_val);
+
+ get_time(&t1);
+ buffer_len = fread(input_buf, sizeof(uint8_t), buf_len, sfp);
+ get_time_and_compute_duration(&t1, &t2, &elapsed);
+ perf_meas[FREAD] = elapsed;
+ printf("\nDEBUG, after fread, buffer_len = %d\n", (int)buffer_len);
+
+ // Read from File
+ uint64_t file_offset = 0;
+ get_time(&t1);
+ file_offset = ftell(sfp);
+ get_time_and_compute_duration(&t1, &t2, &elapsed);
+ perf_meas[FTELL] = elapsed;
+ printf("\nDEBUG: File offset = %lu\n", file_offset);
+
+ ret_val = feof(sfp);
+ printf("DEBUG, after feof, ret_val = %d\n", (int)ret_val);
+
+ clearerr(sfp);
+ printf("DEBUG, after clearerr\n");
+
+ ret_val = feof(sfp);
+ printf("DEBUG, after feof, ret_val = %d\n", (int)ret_val);
+
+ get_time(&t1);
+ ret_val = fclose(sfp);
+ get_time_and_compute_duration(&t1, &t2, &elapsed);
+ perf_meas[FCLOSE] = elapsed;
+ printf("DEBUG, after fclose, ret_val = %d\n", (int)ret_val);
+
+ // ret_val = remove(path_to_file);
+ // printf("DEBUG, after remove, ret_val = %d\n", (int)ret_val);
+
+ return ret_val;
+}
+
+void pfs_run_perf_meas_test(const char* path_to_file) {
+ struct timeval t1, t2;
+ float elapsed;
+ unsigned int i;
+
+ printf("%s: %d\n", __func__, __LINE__);
+
+ if (!path_to_file)
+ return;
+
+ printf("runs=%lu, perf=%lu, val=%lu\n", sizeof(runs), sizeof(struct perf_run),
+ sizeof(runs) / sizeof(struct perf_run));
+
+ for (i = 0; i < sizeof(runs) / sizeof(struct perf_run); i++) {
+ get_time(&t1);
+ pfs_perf_meas_test(path_to_file, runs[i].ptr_to_buf, runs[i].buf_len);
+ get_time_and_compute_duration(&t1, &t2, &elapsed);
+ printf(
+ "time taken by pfs_perf_meas_test for NON_PFS: %f sec, "
+ "buf_size=%lu\n",
+ elapsed, runs[i].buf_len);
+ print_perf_meas(runs[i].buf_len, 0);
+ }
+
+ for (i = 0; i < sizeof(runs) / sizeof(struct perf_run); i++) {
+ get_time(&t1);
+ pfs_perf_meas_test(path_to_file, runs[i].ptr_to_buf, runs[i].buf_len);
+ get_time_and_compute_duration(&t1, &t2, &elapsed);
+ printf(
+ "time taken by pfs_perf_meas_test for PFS: %f sec, "
+ "buf_size=%lu\n",
+ elapsed, runs[i].buf_len);
+ print_perf_meas(runs[i].buf_len, 1);
+ }
+
+ return;
+}
diff --git a/pfs/apps/pfs_app/perf_meas.h b/pfs/apps/pfs_app/perf_meas.h
new file mode 100644
index 0000000..079780a
--- /dev/null
+++ b/pfs/apps/pfs_app/perf_meas.h
@@ -0,0 +1,64 @@
+/*
+ * License: BSD 3-Clause "New" or "Revised" License
+ *
+ * Other web pages for this license
+ * http://www.opensource.org/licenses/BSD-3-Clause
+ *
+ * Copyright (C) 2019 Intel Corporation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef _PERF_MEAS_H_
+#define _PERF_MEAS_H_
+
+#include
+#include "stddef.h"
+#include "stdint.h"
+#include "stdio.h"
+
+/* TODO: although we can get perf measurements for
+ individual apis, for varying buffer sizes for fread/fwrite etc...
+ depending on the current file size...the time for fread/fwrite..
+ can vary...given that it needs to update the hash values in MHT.
+ So, we need to have another test wrapper..that runs
+ these cases(1K,2K,4K buf sizes..etc) for various file sizes..*/
+enum apis_measured { FOPEN = 0, FREAD, FWRITE, FFLUSH, FSEEK, FTELL, FCLOSE, MAX_APIS };
+
+struct perf_run {
+ uint8_t* ptr_to_buf;
+ size_t buf_len;
+};
+
+void get_time(struct timeval* time);
+void compute_duration(struct timeval* t1, struct timeval* t2, float* elapsed);
+void get_time_and_compute_duration(struct timeval* t1, struct timeval* t2, float* elapsed);
+
+void pfs_run_perf_meas_test(const char* path_to_file);
+
+#endif //_PERF_MEAS_H_
diff --git a/pfs/apps/pfs_app/pfs_app.cpp b/pfs/apps/pfs_app/pfs_app.cpp
new file mode 100644
index 0000000..1614584
--- /dev/null
+++ b/pfs/apps/pfs_app/pfs_app.cpp
@@ -0,0 +1,104 @@
+/*
+ * License: BSD 3-Clause "New" or "Revised" License
+ *
+ * Other web pages for this license
+ * http://www.opensource.org/licenses/BSD-3-Clause
+ *
+ * Copyright (C) 2019 Intel Corporation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "pfs_debug.h"
+
+#include "perf_meas.h"
+#include "pfs_app.h"
+#include "pfs_dirops.h"
+
+int main() {
+ printf("%s, pass\n", __func__);
+
+#ifdef BASIC_SANITY_TEST_FOR_SUPPORTED_APIS_AND_READDIR_TEST
+ test_for_apis_supported_for_protected_files(PATH_TO_NON_PFS_TESTFILE, NORMAL);
+ test_for_apis_supported_for_protected_files(PATH_TO_PFS_TESTFILE1, PROTECTED);
+ /* Test files get removed, in *supported* api above.
+ * re-creating , test files to test recursive listing of
+ files(with file-names decrypted for protected files). */
+ create_test_file(PATH_TO_NON_PFS_TESTFILE);
+ create_test_file(PATH_TO_PFS_TESTFILE1);
+ create_test_file(PATH_TO_PFS_TESTFILE2);
+ pfs_readdir_test();
+#endif
+
+#ifdef PFS_UNSUPPORTED_APIS_TEST
+ test_for_apis_unsupported_for_protected_files(PATH_TO_NON_PFS_TESTFILE, NORMAL);
+ test_for_apis_unsupported_for_protected_files(PATH_TO_PFS_TESTFILE1, PROTECTED);
+#endif
+
+#ifdef PFS_BLOCKING_APIS_THAT_RETURN_FILE_DESCRIPTOR
+ test_for_blocking_apis_that_return_file_descriptor(PATH_TO_NON_PFS_TESTFILE, NORMAL);
+ test_for_blocking_apis_that_return_file_descriptor(PATH_TO_PFS_TESTFILE1, PROTECTED);
+#endif
+
+#ifdef PFS_MISC_TEST_CASES
+ test_for_misc_test_cases1(PATH_TO_NON_PFS_TESTFILE, NORMAL);
+ test_for_misc_test_cases1(PATH_TO_PFS_TESTFILE1, PROTECTED);
+ test_for_misc_test_cases2();
+#endif
+
+#ifdef PFS_DIR_APIS_TESTING
+ pfs_directory_system_apis_test();
+#endif
+
+#ifdef PFS_64BIT_API_TEST_CASES
+ test_for_64bit_apis(PATH_TO_NON_PFS_TESTFILE, NORMAL);
+ test_for_64bit_apis(PATH_TO_PFS_TESTFILE1, PROTECTED);
+#endif
+
+#ifdef PFS_WIDECHAR_UNSUPPORTED_APIS_TEST
+ test_for_wide_char_apis_unsupported(PATH_TO_NON_PFS_TESTFILE3, NORMAL);
+ test_for_wide_char_apis_unsupported(PATH_TO_PFS_TESTFILE3, PROTECTED);
+#endif
+
+#ifdef PFS_CONVERT_NORMAL_FILES_TO_PROTECTED_FILES
+ protect_files(CLEAR_DIR_PATH, PROTECTED_DIR_PATH);
+#endif
+
+#ifdef PFS_API_PERF_MEAS
+ pfs_run_perf_meas_test(PATH_TO_PFS_TESTFILE1);
+#endif
+
+ return 0;
+}
diff --git a/pfs/apps/pfs_app/pfs_app.h b/pfs/apps/pfs_app/pfs_app.h
new file mode 100644
index 0000000..39c4793
--- /dev/null
+++ b/pfs/apps/pfs_app/pfs_app.h
@@ -0,0 +1,104 @@
+/*
+ * License: BSD 3-Clause License
+ *
+ * Copyright (C) 2019 Intel Corporation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef _PFS_APP_H_
+#define _PFS_APP_H_
+
+#include "pfs_plus.h"
+
+/* Note: When application sets path to directory-path(and-also
+ * when setting path in manifest),
+ * there should NOT be any trailing backslash(/) */
+#define PROTECTED_DIR_PATH "/pfs_dir/secrets"
+#define CLEAR_DIR_PATH "/pfs_dir/non_secrets"
+// Note: Below path mounted in manifest
+#define TEST_DIR_PATH "/pfs_dir/test_dir"
+
+#define FILENAME_MAX_LENGTH (PFS_FILENAME_MAX_LENGTH + 30)
+
+#define FILE_PATH_MAX (4096)
+#define MAX_SIZE_FOR_FILE_READ (512)
+
+#define PATH_TO_PFS_TESTFILE1 "/pfs_dir/secrets/sub_dir1/pfs_file1"
+#define PATH_TO_PFS_TESTFILE2 "/pfs_dir/secrets/sub_dir1/pfs_file2"
+#define PATH_TO_PFS_TESTFILE3 "/pfs_dir/secrets/sub_dir1/pfs_file3"
+
+#define PATH_TO_NON_PFS_TESTFILE "/pfs_dir/non_secrets/non_pfs_file1"
+#define PATH_TO_NON_PFS_TESTFILE2 "/pfs_dir/non_secrets/non_pfs_file2"
+#define PATH_TO_NON_PFS_TESTFILE3 "/pfs_dir/non_secrets/non_pfs_file3"
+
+#define BUFFER_SIZE (128)
+#define SPRINTF_BUFSIZE (300)
+
+/* Note: Enable testing for different categories of system-apis,
+using macros below. */
+#define BASIC_SANITY_TEST_FOR_SUPPORTED_APIS_AND_READDIR_TEST
+//#define PFS_UNSUPPORTED_APIS_TEST
+//#define PFS_BLOCKING_APIS_THAT_RETURN_FILE_DESCRIPTOR
+//#define PFS_MISC_TEST_CASES
+//#define PFS_64BIT_API_TEST_CASES
+//#define PFS_WIDECHAR_UNSUPPORTED_APIS_TEST
+//#define PFS_DIR_APIS_TESTING
+
+//#define PFS_CONVERT_NORMAL_FILES_TO_PROTECTED_FILES
+//#define PFS_API_PERF_MEAS
+
+#define ZERO_RESULT(ret_val) ((ret_val == 0) ? "PASS" : "ERROR")
+#define EXPECTED_TRUE(result) ((result == 1) ? "PASS" : "ERROR")
+#define FILE_TYPE_STRING(file_type) ((file_type == PROTECTED) ? "PROTECTED" : "NORMAL")
+
+typedef enum file_type { NORMAL, PROTECTED, NOT_APPLICABLE } file_type_t;
+
+int open_file_wrapper(const char* path_to_file, FILE** fp);
+int create_test_file(const char* path_to_file);
+
+int test_for_apis_supported_for_protected_files(const char* path_to_file, file_type_t file_type);
+int test_for_apis_unsupported_for_protected_files(const char* path_to_file, file_type_t file_type);
+
+int test_for_blocking_apis_that_return_file_descriptor(const char* path_to_file,
+ file_type_t file_type);
+int test_for_misc_test_cases1(const char* path_to_file, file_type_t file_type);
+int test_for_misc_test_cases2();
+
+int test_for_wide_char_apis_unsupported(const char* path_to_file, file_type_t file_type);
+int test_for_64bit_apis(const char* path_to_file, file_type_t file_type);
+
+int protect_files(char* src_dir_path, char* dest_dir_path);
+
+int check_ret_and_print_dbg(const char* func, file_type_t file_type, int ret_val);
+int check_ptr_and_print_dbg(const char* func, file_type_t file_type, void* ptr);
+int check_fd_and_print_dbg(const char* func, file_type_t file_type, int fd);
+int check_errno_and_print_dbg(const char* func, file_type_t file_type, wint_t ret_val);
+int check_bool_and_print_dbg(const char* func, file_type_t file_type, bool result, char* dbg_str);
+
+#endif /* _PFS_APP_H_ */
diff --git a/pfs/apps/pfs_app/pfs_app.manifest.template b/pfs/apps/pfs_app/pfs_app.manifest.template
new file mode 100644
index 0000000..277b84b
--- /dev/null
+++ b/pfs/apps/pfs_app/pfs_app.manifest.template
@@ -0,0 +1,79 @@
+#!$(PAL)
+
+loader.preload = file:../../deps/graphene/Runtime/libsysdb.so
+loader.exec = file:pfs_app
+loader.execname = pfs_app
+loader.env.PATH = /:/usr/sbin:/usr/bin:/sbin:/bin
+loader.env.LD_LIBRARY_PATH = /lib:/lib/x86_64-linux-gnu:/usr/lib/x86_64-linux-gnu
+loader.env.USERNAME =
+loader.env.HOME =
+loader.env.PWD =
+loader.env.PFS_MOUNT_POINT = /pfs_dir/secrets
+loader.env.PFS_USE_CUSTOM_KEY = no
+loader.env.LD_PRELOAD = libfileops_interceptor.so
+#loader.env.LD_DEBUG = all
+loader.env.HOSTNAME = test
+loader.debug_type = inline
+loader.syscall_symbol = syscalldb
+
+fs.mount.lib1.type = chroot
+fs.mount.lib1.path = /lib
+fs.mount.lib1.uri = file:../../deps/graphene/Runtime/
+
+fs.mount.lib2.type = chroot
+fs.mount.lib2.path = /lib/x86_64-linux-gnu
+fs.mount.lib2.uri = file:/lib/x86_64-linux-gnu
+
+fs.mount.usr.type = chroot
+fs.mount.usr.path = /usr
+fs.mount.usr.uri = file:/usr
+
+#Below mount point needed for libstdc++, also mount rules for sub-directories
+#under a given directory, lets say /usr, should be below the top-level /usr mount rule.
+#Just like /lib mount rules above.
+fs.mount.lib3.type = chroot
+fs.mount.lib3.path = /usr/lib/x86_64-linux-gnu
+fs.mount.lib3.uri = file:/usr/lib/x86_64-linux-gnu
+
+fs.mount.bin.type = chroot
+fs.mount.bin.path = /bin
+fs.mount.bin.uri = file:/bin
+
+fs.mount.etc.type = chroot
+fs.mount.etc.path = /etc
+fs.mount.etc.uri = file:
+
+fs.mount.pfs.type = chroot
+fs.mount.pfs.path = /pfs_dir
+fs.mount.pfs.uri = file:/home/skris14/pfs_mount
+
+# allow to bind on port 8000
+net.allow_bind.1 = 127.0.0.1:8000
+# allow to connect to port 8000
+net.allow_peer.1 = 127.0.0.1:8000
+
+# sgx-related
+sys.stack.size = 1m
+sys.brk.size = 64M
+glibc.heap_size = 16M
+#sgx.enclave_size = $(MEMSIZE)
+sgx.enclave_size = 1G
+sgx.thread_num = 4
+#sgx.thread_num = $(THREADNUM)
+
+sgx.trusted_files.ld = file:../../deps/graphene/Runtime//ld-linux-x86-64.so.2
+sgx.trusted_files.libc = file:../../deps/graphene/Runtime//libc.so.6
+sgx.trusted_files.libdl = file:../../deps/graphene/Runtime//libdl.so.2
+sgx.trusted_files.libm = file:../../deps/graphene/Runtime//libm.so.6
+sgx.trusted_files.libpthread = file:../../deps/graphene/Runtime//libpthread.so.0
+sgx.trusted_files.libcrypt = file:/lib/x86_64-linux-gnu/libcrypt.so.1
+sgx.trusted_files.libstdcplusplus = file:/usr/lib/x86_64-linux-gnu/libstdc++.so.6
+sgx.trusted_files.libgcc = file:/lib/x86_64-linux-gnu/libgcc_s.so.1
+sgx.trusted_files.libfops = file:../../deps/graphene/Runtime//libfileops_interceptor.so
+sgx.trusted_files.sealed_custom_key = file:sealed_custom_key
+
+#Note: Access permissions applies to sub-directories recursively.
+#WARNING: There should NOT be any / at the end of the directory-path below, it breaks the
+#allowed_files functionality graphenes, so even for files that do NOT exist(for example
+#volume-meta-data, graphene returns true(as if file exists).
+sgx.allowed_files.mount_path = file:/home/skris14/pfs_mount
diff --git a/pfs/apps/pfs_app/pfs_create_protected_files.cpp b/pfs/apps/pfs_app/pfs_create_protected_files.cpp
new file mode 100644
index 0000000..73178b4
--- /dev/null
+++ b/pfs/apps/pfs_app/pfs_create_protected_files.cpp
@@ -0,0 +1,351 @@
+/*
+ * License: BSD 3-Clause "New" or "Revised" License
+ *
+ * Other web pages for this license
+ * http://www.opensource.org/licenses/BSD-3-Clause
+ *
+ * Copyright (C) 2019 Intel Corporation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "sgx_tseal.h"
+
+#include "dirops_typedefs.h"
+#include "fileops_typedefs.h"
+#include "pfs_debug.h"
+
+#include "perf_meas.h"
+#include "pfs_app.h"
+#include "pfs_dirops.h"
+
+static int pfs_create_new_file(const char* prot_path, const char* filename, FILE** sfp);
+static int protect_clear_file(const char* clear_path, const char* clear_file,
+ const char* prot_path);
+
+/* if file already exists, returns error */
+static int pfs_create_new_file(const char* prot_path, const char* filename, FILE** sfp) {
+ uint32_t full_path_len = 0;
+ char* full_path = NULL;
+ int ret = 0;
+
+ if (!filename || !sfp || !prot_path)
+ return -1;
+
+ printf("filename is =%s\n", filename);
+
+ full_path_len = strlen(prot_path) + 1 + strlen(filename) + 1;
+
+ if (full_path_len + 1 > FILE_PATH_MAX) {
+ printf("file_path=%s too long, length=%d\n", full_path, full_path_len);
+ return -1;
+ }
+
+ full_path = (char*)calloc(full_path_len + 1, 1);
+
+ if (!full_path)
+ return -1;
+
+ strncpy(full_path, prot_path, strlen(prot_path));
+ full_path[strlen(prot_path)] = '/';
+ strncpy(full_path + strlen(prot_path) + 1, filename, strlen(filename));
+
+ printf("full_path=%s\n", full_path);
+
+ *sfp = fopen(full_path, "rb");
+
+ if (*sfp == NULL) {
+ printf("File does NOT exist, need to CREATE one\n");
+
+ *sfp = fopen(full_path, "w+b");
+
+ if (*sfp == NULL) {
+ printf("File does NOT exist, error in creating file\n");
+ ret = -1;
+ goto exit;
+ }
+ } else if (*sfp != NULL) {
+ printf("File ALREADY exists.\n");
+ ret = -1;
+ goto exit;
+ }
+
+exit:
+
+ if (full_path)
+ free(full_path);
+
+ return ret;
+}
+
+/* opens existing clear file, and outputs protected file */
+static int protect_clear_file(const char* clear_path, const char* clear_file,
+ const char* prot_path) {
+ char* buffer = NULL;
+ int file_size = 0;
+
+ ssize_t bytes_read = 0;
+ ssize_t read_length = 0;
+ ssize_t bytes_written = 0;
+
+ int bytes_written_total = 0;
+ int bytes_read_total = 0;
+
+ FILE* fclear = NULL;
+ int ret_val = 0;
+ char* full_path = NULL;
+ uint32_t full_path_len = 0;
+
+ FILE* sfp = NULL;
+
+ if (!clear_file || !clear_path || !prot_path)
+ return -1;
+
+ full_path_len = strlen(clear_path) + 1 + strlen(clear_file) + 1;
+
+ if (full_path_len + 1 > FILE_PATH_MAX) {
+ printf("file_path=%s too long, file_size=%d\n", full_path, full_path_len);
+ return -1;
+ }
+
+ full_path = (char*)calloc(full_path_len + 1, 1);
+
+ if (!full_path)
+ return -1;
+
+ strncpy(full_path, clear_path, strlen(clear_path));
+ full_path[strlen(clear_path)] = '/';
+ strncpy(full_path + strlen(clear_path) + 1, clear_file, strlen(clear_file));
+
+ printf("full_path=%s\n", full_path);
+
+ fclear = fopen(full_path, "rb");
+
+ if (!fclear) {
+ printf("file doesnt exist, errno=%d, full_path=%s\n", errno, full_path);
+ ret_val = -1;
+ goto exit;
+ }
+
+ ret_val = fseek(fclear, 0, SEEK_END);
+
+ if (ret_val == -1) {
+ goto exit;
+ }
+
+ file_size = ftell(fclear);
+
+ if (file_size == -1 || file_size == 0) {
+ ret_val = -1;
+ goto exit;
+ }
+
+ ret_val = fseek(fclear, 0, SEEK_SET);
+
+ if (ret_val == -1) {
+ goto exit;
+ }
+
+ printf("Length of file=%s, is =%d\n", full_path, file_size);
+
+ if (MAX_SIZE_FOR_FILE_READ < file_size) {
+ read_length = MAX_SIZE_FOR_FILE_READ;
+ } else
+ read_length = file_size;
+
+ buffer = (char*)malloc(read_length);
+
+ if (!buffer) {
+ ret_val = -1;
+ goto exit;
+ }
+
+ bytes_read_total = 0;
+
+ // opening the protected file.
+ ret_val = pfs_create_new_file(prot_path, clear_file, &sfp);
+
+ if (ret_val != 0) {
+ ret_val = -1;
+ goto exit;
+ }
+
+ while (bytes_read_total < file_size) {
+ bytes_read = fread(buffer, sizeof(uint8_t), read_length, fclear);
+
+ printf("Length of buffer is =%lu, bytes read=%lu\n", read_length, bytes_read);
+
+ if (bytes_read != read_length) {
+ ret_val = ferror(fclear);
+
+ if (ret_val != 0) {
+ printf("error in fread=%d\n", ret_val);
+ break;
+ }
+ }
+
+ // Write to protected file
+ bytes_written = fwrite(buffer, sizeof(uint8_t), bytes_read, sfp);
+ printf("Size of Write= %lu\n", bytes_written);
+
+ if (bytes_written != bytes_read) {
+ printf("error, ret=%d, size of Write=%lu, bytes_read=%lu\n", ret_val, bytes_written,
+ bytes_read);
+ break;
+ }
+
+ // to protected_file.
+ bytes_written_total = bytes_written_total + bytes_read;
+
+ bytes_read_total = bytes_read_total + bytes_read;
+
+ if (file_size > bytes_read_total) {
+ if ((file_size - bytes_read_total) > MAX_SIZE_FOR_FILE_READ)
+ read_length = MAX_SIZE_FOR_FILE_READ;
+ else
+ read_length = file_size - bytes_read_total;
+ }
+ }
+
+ if (ret_val == 0) {
+ printf("file_size =%d, bytes_read_total=%d, bytes_written_total=%d\n", file_size,
+ bytes_read_total, bytes_written_total);
+ }
+
+exit:
+ if (full_path)
+ free(full_path);
+
+ if (buffer)
+ free(buffer);
+
+ if (sfp)
+ fclose(sfp);
+
+ if (fclear)
+ fclose(fclear);
+
+ return ret_val;
+}
+
+/* Recursively dives into the source directory,
+ * and creates protected files into the destination directory.
+ * It creates new sub-directories in destination, to duplicate
+ * the directory-tree from source to destination, and transforms.
+ * clear files into protected files.
+ */
+int protect_files(char* src_dir_path, char* dest_dir_path) {
+ int ret = 0;
+
+ DIR* src_dir_ptr;
+ struct dirent* entry;
+ char* src_file_path = NULL;
+ char* dest_file_path = NULL;
+
+ if (!src_dir_path || !dest_dir_path)
+ return -1;
+
+ if (!(src_dir_ptr = opendir(src_dir_path)))
+ return -1;
+
+ printf("%s: recursive listing, parent src_dir_ptr=%s\n", __func__, src_dir_path);
+
+ while ((entry = readdir(src_dir_ptr)) != NULL) {
+ if (entry->d_type == DT_DIR) {
+ if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
+ continue;
+
+ src_file_path = (char*)calloc(strlen(src_dir_path) + 1 + strlen(entry->d_name) + 1, 1);
+
+ if (!src_file_path) {
+ printf("calloc fails\n");
+ goto exit;
+ }
+
+ strncpy(src_file_path, src_dir_path, strlen(src_dir_path));
+ src_file_path[strlen(src_dir_path)] = '/';
+ strncpy(src_file_path + strlen(src_dir_path) + 1, entry->d_name, strlen(entry->d_name));
+
+ dest_file_path =
+ (char*)calloc(strlen(dest_dir_path) + 1 + strlen(entry->d_name) + 1, 1);
+
+ if (!dest_file_path) {
+ printf("calloc fails\n");
+ goto exit;
+ }
+
+ strncpy(dest_file_path, dest_dir_path, strlen(dest_dir_path));
+ dest_file_path[strlen(dest_dir_path)] = '/';
+ strncpy(dest_file_path + strlen(dest_dir_path) + 1, entry->d_name,
+ strlen(entry->d_name));
+
+ if ((ret = mkdir(dest_file_path, 0775) != 0) && (errno != EEXIST)) {
+ printf("mkdir fails for->%s, errno=%d\n", dest_file_path, errno);
+ goto exit;
+ }
+
+ printf("[DIRECTORY->%s], type->%d, src_path->%s, dest_path->%s\n", entry->d_name,
+ entry->d_type, src_file_path, dest_file_path);
+ protect_files(src_file_path, dest_file_path);
+ } else if (entry->d_type == DT_REG) {
+ printf("FILE-> %s, type->%d\n", entry->d_name, entry->d_type);
+ protect_clear_file(src_dir_path, entry->d_name, dest_dir_path);
+ } else {
+ printf("No-op for FILE-> %s, type->%d\n", entry->d_name, entry->d_type);
+ }
+ }
+
+exit:
+
+ if (src_file_path) {
+ free(src_file_path);
+ src_file_path = NULL;
+ }
+
+ if (dest_file_path) {
+ free(dest_file_path);
+ dest_file_path = NULL;
+ }
+
+ closedir(src_dir_ptr);
+
+ return ret;
+}
diff --git a/pfs/apps/pfs_app/pfs_dirops.cpp b/pfs/apps/pfs_app/pfs_dirops.cpp
new file mode 100644
index 0000000..df3fd6b
--- /dev/null
+++ b/pfs/apps/pfs_app/pfs_dirops.cpp
@@ -0,0 +1,759 @@
+/*
+ * License: BSD 3-Clause License
+ *
+ * Copyright (C) 2019 Intel Corporation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+
+#include
+#include
+#include
+
+#include "fileops_typedefs.h"
+#include "perf_meas.h"
+#include "pfs_app.h"
+#include "pfs_debug.h"
+
+static void using_readdir_api(const char* name);
+static void using_readdir64_api(const char* name);
+
+static void using_readdir_r_api(const char* name);
+static void using_readdir64_r_api(const char* name);
+
+static int using_scandir_api(const char* dir_path);
+static int using_scandir64_api(const char* dir_path);
+static int using_scandirat_api(const char* dir_path);
+static int using_scandirat64_api(const char* dir_path);
+
+static void using_readdir_api(const char* name) {
+ DIR* dir;
+ struct dirent* entry;
+ char* file_path = NULL;
+
+ if (!(dir = opendir(name)))
+ return;
+
+ printf("%s: recursive listing, parent dir=%s\n", __func__, name);
+
+ while ((entry = readdir(dir)) != NULL) {
+ if (entry->d_type == DT_DIR) {
+ if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
+ continue;
+
+ file_path = (char*)calloc(strlen(name) + 1 + strlen(entry->d_name) + 1, 1);
+
+ if (!file_path) {
+ printf("calloc fails\n");
+ continue;
+ }
+
+ strncpy(file_path, name, strlen(name));
+ file_path[strlen(name)] = '/';
+ strncpy(file_path + strlen(name) + 1, entry->d_name, strlen(entry->d_name));
+
+ printf("[DIRECTORY->%s], type->%d\n", entry->d_name, entry->d_type);
+ using_readdir_api(file_path);
+ } else {
+ printf("FILE-> %s, type->%d\n", entry->d_name, entry->d_type);
+ }
+ }
+
+ if (file_path) {
+ free(file_path);
+ file_path = NULL;
+ }
+
+ closedir(dir);
+}
+
+static void using_readdir64_api(const char* name) {
+ DIR* dir;
+ struct dirent64* entry;
+ char* file_path = NULL;
+
+ if (!(dir = opendir(name)))
+ return;
+
+ printf("%s: recursive listing, parent dir=%s\n", __func__, name);
+
+ while ((entry = readdir64(dir)) != NULL) {
+ if (entry->d_type == DT_DIR) {
+ if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
+ continue;
+
+ file_path = (char*)calloc(strlen(name) + 1 + strlen(entry->d_name) + 1, 1);
+
+ if (!file_path) {
+ printf("calloc fails\n");
+ continue;
+ }
+
+ strncpy(file_path, name, strlen(name));
+ file_path[strlen(name)] = '/';
+ strncpy(file_path + strlen(name) + 1, entry->d_name, strlen(entry->d_name));
+
+ printf("[DIRECTORY->%s], type->%d\n", entry->d_name, entry->d_type);
+ using_readdir64_api(file_path);
+ } else {
+ printf("FILE-> %s, type->%d\n", entry->d_name, entry->d_type);
+ }
+ }
+
+ if (file_path) {
+ free(file_path);
+ file_path = NULL;
+ }
+
+ closedir(dir);
+}
+
+static void using_readdir_r_api(const char* name) {
+ DIR* dir;
+ struct dirent entry;
+ struct dirent* result = NULL;
+ char* file_path = NULL;
+ int ret = 0;
+
+ if (!(dir = opendir(name)))
+ return;
+
+ printf("%s: recursive listing, parent dir=%s\n", __func__, name);
+
+ memset(&entry, 0, sizeof(entry));
+
+ while ((ret = readdir_r(dir, &entry, &result)) == 0 && result != NULL) {
+ if (entry.d_type == DT_DIR) {
+ if (strcmp(entry.d_name, ".") == 0 || strcmp(entry.d_name, "..") == 0)
+ continue;
+
+ file_path = (char*)calloc(strlen(name) + 1 + strlen(entry.d_name) + 1, 1);
+
+ if (!file_path) {
+ printf("calloc fails\n");
+ continue;
+ }
+
+ strncpy(file_path, name, strlen(name));
+ file_path[strlen(name)] = '/';
+ strncpy(file_path + strlen(name) + 1, entry.d_name, strlen(entry.d_name));
+
+ printf("[DIRECTORY->%s], type->%d\n", entry.d_name, entry.d_type);
+ using_readdir_r_api(file_path);
+ } else {
+ printf("FILE-> %s, type->%d\n", entry.d_name, entry.d_type);
+ }
+ }
+
+ if (file_path) {
+ free(file_path);
+ file_path = NULL;
+ }
+
+ closedir(dir);
+}
+
+static void using_readdir64_r_api(const char* name) {
+ DIR* dir;
+ struct dirent64 entry;
+ struct dirent64* result = NULL;
+ char* file_path = NULL;
+ int ret = 0;
+
+ if (!(dir = opendir(name)))
+ return;
+
+ printf("%s: recursive listing, parent dir=%s\n", __func__, name);
+
+ memset(&entry, 0, sizeof(entry));
+
+ while ((ret = readdir64_r(dir, &entry, &result)) == 0 && result != NULL) {
+ if (entry.d_type == DT_DIR) {
+ if (strcmp(entry.d_name, ".") == 0 || strcmp(entry.d_name, "..") == 0)
+ continue;
+
+ file_path = (char*)calloc(strlen(name) + 1 + strlen(entry.d_name) + 1, 1);
+
+ if (!file_path) {
+ printf("calloc fails\n");
+ continue;
+ }
+
+ strncpy(file_path, name, strlen(name));
+ file_path[strlen(name)] = '/';
+ strncpy(file_path + strlen(name) + 1, entry.d_name, strlen(entry.d_name));
+
+ printf("[DIRECTORY->%s], type->%d\n", entry.d_name, entry.d_type);
+ using_readdir64_r_api(file_path);
+ } else {
+ printf("FILE-> %s, type->%d\n", entry.d_name, entry.d_type);
+ }
+ }
+
+ if (file_path) {
+ free(file_path);
+ file_path = NULL;
+ }
+
+ closedir(dir);
+}
+
+static int using_scandir_api(const char* dir_path) {
+ struct dirent** namelist;
+ int n;
+ char* file_path = NULL;
+
+ if (!dir_path)
+ return -1;
+
+ n = scandir(dir_path, &namelist, NULL, alphasort);
+
+ printf("%s:%d: dir_path=%s, n=%d\n", __func__, __LINE__, dir_path, n);
+
+ if (n < 0) {
+ perror("scandir");
+ return n;
+ }
+
+ while (n--) {
+ printf("%s\n", namelist[n]->d_name);
+
+ if (namelist[n]->d_type == DT_DIR) {
+ if (strcmp(namelist[n]->d_name, ".") == 0 || strcmp(namelist[n]->d_name, "..") == 0)
+ continue;
+
+ file_path = (char*)calloc(strlen(dir_path) + 1 + strlen(namelist[n]->d_name) + 1, 1);
+
+ if (!file_path) {
+ printf("calloc fails\n");
+ continue;
+ }
+
+ strncpy(file_path, dir_path, strlen(dir_path));
+ file_path[strlen(dir_path)] = '/';
+ strncpy(file_path + strlen(dir_path) + 1, namelist[n]->d_name,
+ strlen(namelist[n]->d_name));
+
+ printf("[DIRECTORY->%s], type->%d\n", namelist[n]->d_name, namelist[n]->d_type);
+ using_scandir_api(file_path);
+ } else {
+ printf("FILE-> %s, type->%d\n", namelist[n]->d_name, namelist[n]->d_type);
+ }
+
+ free(namelist[n]);
+ }
+
+ free(namelist);
+
+ if (file_path) {
+ free(file_path);
+ file_path = NULL;
+ }
+
+ return 0;
+}
+
+static int using_scandir64_api(const char* dir_path) {
+ struct dirent64** namelist;
+ int n;
+ char* file_path = NULL;
+
+ if (!dir_path)
+ return -1;
+
+ n = scandir64(dir_path, &namelist, NULL, NULL);
+
+ printf("%s:%d: dir_path=%s, n=%d\n", __func__, __LINE__, dir_path, n);
+
+ if (n < 0) {
+ perror("scandir64");
+ return n;
+ }
+
+ while (n--) {
+ printf("%s\n", namelist[n]->d_name);
+
+ if (namelist[n]->d_type == DT_DIR) {
+ if (strcmp(namelist[n]->d_name, ".") == 0 || strcmp(namelist[n]->d_name, "..") == 0)
+ continue;
+
+ file_path = (char*)calloc(strlen(dir_path) + 1 + strlen(namelist[n]->d_name) + 1, 1);
+
+ if (!file_path) {
+ printf("calloc fails\n");
+ continue;
+ }
+ strncpy(file_path, dir_path, strlen(dir_path));
+ file_path[strlen(dir_path)] = '/';
+ strncpy(file_path + strlen(dir_path) + 1, namelist[n]->d_name,
+ strlen(namelist[n]->d_name));
+
+ printf("[DIRECTORY->%s], type->%d\n", namelist[n]->d_name, namelist[n]->d_type);
+ using_scandir64_api(file_path);
+ } else {
+ printf("FILE-> %s, type->%d\n", namelist[n]->d_name, namelist[n]->d_type);
+ }
+
+ free(namelist[n]);
+ }
+
+ free(namelist);
+
+ if (file_path) {
+ free(file_path);
+ file_path = NULL;
+ }
+
+ return 0;
+}
+
+static int using_scandirat_api(const char* dir_path) {
+ struct dirent** namelist;
+ int n;
+ char* file_path = NULL;
+
+ if (!dir_path)
+ return -1;
+
+ // note: passing absolute path, so fd can be NULL(i.e. it is ignored).
+ n = scandirat(NULL, dir_path, &namelist, NULL, NULL);
+
+ printf("%s:%d: dir_path=%s, n=%d\n", __func__, __LINE__, dir_path, n);
+
+ if (n < 0) {
+ perror("scandirat");
+ return n;
+ }
+
+ while (n--) {
+ printf("%s\n", namelist[n]->d_name);
+
+ if (namelist[n]->d_type == DT_DIR) {
+ if (strcmp(namelist[n]->d_name, ".") == 0 || strcmp(namelist[n]->d_name, "..") == 0)
+ continue;
+
+ file_path = (char*)calloc(strlen(dir_path) + 1 + strlen(namelist[n]->d_name) + 1, 1);
+
+ if (!file_path) {
+ printf("calloc fails\n");
+ continue;
+ }
+
+ strncpy(file_path, dir_path, strlen(dir_path));
+ file_path[strlen(dir_path)] = '/';
+ strncpy(file_path + strlen(dir_path) + 1, namelist[n]->d_name,
+ strlen(namelist[n]->d_name));
+
+ printf("[DIRECTORY->%s], type->%d\n", namelist[n]->d_name, namelist[n]->d_type);
+ using_scandirat_api(file_path);
+ } else {
+ printf("FILE-> %s, type->%d\n", namelist[n]->d_name, namelist[n]->d_type);
+ }
+
+ free(namelist[n]);
+ }
+
+ free(namelist);
+
+ if (file_path) {
+ free(file_path);
+ file_path = NULL;
+ }
+
+ return 0;
+}
+
+static int using_scandirat64_api(const char* dir_path) {
+ struct dirent64** namelist;
+ int n;
+ char* file_path = NULL;
+
+ if (!dir_path)
+ return -1;
+
+ // note: passing absolute path, so fd can be NULL(i.e. it is ignored).
+ n = scandirat64(NULL, dir_path, &namelist, NULL, NULL);
+
+ printf("%s:%d: dir_path=%s, n=%d\n", __func__, __LINE__, dir_path, n);
+
+ if (n < 0) {
+ perror("scandirat64");
+ return n;
+ }
+
+ while (n--) {
+ printf("%s\n", namelist[n]->d_name);
+
+ if (namelist[n]->d_type == DT_DIR) {
+ if (strcmp(namelist[n]->d_name, ".") == 0 || strcmp(namelist[n]->d_name, "..") == 0)
+ continue;
+
+ file_path = (char*)calloc(strlen(dir_path) + 1 + strlen(namelist[n]->d_name) + 1, 1);
+
+ if (!file_path) {
+ printf("calloc fails\n");
+ continue;
+ }
+ strncpy(file_path, dir_path, strlen(dir_path));
+ file_path[strlen(dir_path)] = '/';
+ strncpy(file_path + strlen(dir_path) + 1, namelist[n]->d_name,
+ strlen(namelist[n]->d_name));
+
+ printf("[DIRECTORY->%s], type->%d\n", namelist[n]->d_name, namelist[n]->d_type);
+ using_scandirat64_api(file_path);
+ } else {
+ printf("FILE-> %s, type->%d\n", namelist[n]->d_name, namelist[n]->d_type);
+ }
+
+ free(namelist[n]);
+ }
+
+ free(namelist);
+
+ if (file_path) {
+ free(file_path);
+ file_path = NULL;
+ }
+
+ return 0;
+}
+
+static void using_other_dirops_apis(const char* name) {
+ DIR* dir;
+ struct dirent* entry;
+ char* file_path = NULL;
+ int fd = 0;
+ long int dir_offset = 0;
+
+ if (!(dir = opendir(name)))
+ return;
+
+ printf("%s: recursive listing, parent dir=%s\n", __func__, name);
+
+ fd = dirfd(dir);
+
+ printf("fd=%d after call to dirfd, parent dir path=%s\n", fd, name);
+
+ while ((entry = readdir(dir)) != NULL) {
+ if (entry->d_type == DT_DIR) {
+ if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
+ continue;
+
+ printf("[DIRECTORY->%s], type->%d\n", entry->d_name, entry->d_type);
+ } else {
+ printf("FILE->%s, type->%d\n", entry->d_name, entry->d_type);
+
+ // testing other apis..and then exiting
+ dir_offset = telldir(dir);
+
+ if (dir_offset == -1) {
+ printf("error = %d, from telldir\n", dir_offset);
+ break;
+ } else {
+ seekdir(dir, dir_offset);
+ rewinddir(dir);
+ printf("exiting loop, after other apis are called\n");
+ break;
+ }
+ }
+ }
+
+ if (file_path) {
+ free(file_path);
+ file_path = NULL;
+ }
+
+ closedir(dir);
+}
+
+#ifndef USE_FDS
+#define USE_FDS 16
+#endif
+
+int list_entry(const char* filepath, const struct stat* info, const int typeflag,
+ struct FTW* pathinfo) {
+ if (!filepath || !info || !pathinfo || typeflag < 0) {
+ return -1;
+ }
+
+ return 0;
+}
+
+int using_nftw_api(const char* const dirpath) {
+ int result = 0;
+
+ if (dirpath == NULL || *dirpath == '\0') {
+ return EINVAL;
+ }
+
+ result = nftw(dirpath, list_entry, USE_FDS, FTW_PHYS);
+ if (result >= 0)
+ errno = result;
+
+ return errno;
+}
+
+int list_entry64(const char* filepath, const struct stat64* info, const int typeflag,
+ struct FTW* pathinfo) {
+ if (!filepath || !info || !pathinfo || typeflag < 0) {
+ return -1;
+ }
+
+ return 0;
+}
+
+int using_nftw64_api(const char* const dirpath) {
+ int result = 0;
+
+ if (dirpath == NULL || *dirpath == '\0') {
+ return EINVAL;
+ }
+
+ result = nftw64(dirpath, list_entry64, USE_FDS, FTW_PHYS);
+ if (result >= 0)
+ errno = result;
+
+ return errno;
+}
+
+int pfs_readdir_test() {
+ uint32_t i;
+ int ret_val = 0;
+
+ const char* dir_names_abs[] = {
+ CLEAR_DIR_PATH, PROTECTED_DIR_PATH,
+ };
+
+ printf("%s,%d:\n", __func__, __LINE__);
+
+ for (i = 0; i < sizeof(dir_names_abs) / sizeof(char*); i++) {
+ using_readdir_api(dir_names_abs[i]);
+ }
+
+ return ret_val;
+}
+
+int pfs_readdir64_test() {
+ uint32_t i;
+ int ret_val = 0;
+
+ const char* dir_names_abs[] = {
+ CLEAR_DIR_PATH, PROTECTED_DIR_PATH,
+ };
+
+ printf("%s,%d:\n", __func__, __LINE__);
+
+ for (i = 0; i < sizeof(dir_names_abs) / sizeof(char*); i++) {
+ using_readdir64_api(dir_names_abs[i]);
+ }
+
+ return ret_val;
+}
+
+int pfs_readdir_r_test() {
+ uint32_t i;
+ int ret_val = 0;
+
+ const char* dir_names_abs[] = {
+ CLEAR_DIR_PATH, PROTECTED_DIR_PATH,
+ };
+
+ printf("%s,%d:\n", __func__, __LINE__);
+
+ for (i = 0; i < sizeof(dir_names_abs) / sizeof(char*); i++) {
+ using_readdir_r_api(dir_names_abs[i]);
+ }
+
+ return ret_val;
+}
+
+int pfs_readdir64_r_test() {
+ uint32_t i;
+ int ret_val = 0;
+
+ const char* dir_names_abs[] = {
+ CLEAR_DIR_PATH, PROTECTED_DIR_PATH,
+ };
+
+ printf("%s,%d:\n", __func__, __LINE__);
+
+ for (i = 0; i < sizeof(dir_names_abs) / sizeof(char*); i++) {
+ using_readdir64_r_api(dir_names_abs[i]);
+ }
+
+ return ret_val;
+}
+
+int pfs_scandir_test() {
+ uint32_t i;
+ int ret_val = 0;
+
+ const char* dir_names_abs[] = {
+ CLEAR_DIR_PATH, PROTECTED_DIR_PATH,
+ };
+
+ printf("%s,%d:\n", __func__, __LINE__);
+
+ for (i = 0; i < sizeof(dir_names_abs) / sizeof(char*); i++) {
+ using_scandir_api(dir_names_abs[i]);
+ }
+
+ return ret_val;
+}
+
+int pfs_scandir64_test() {
+ uint32_t i;
+ int ret_val = 0;
+
+ const char* dir_names_abs[] = {
+ CLEAR_DIR_PATH, PROTECTED_DIR_PATH,
+ };
+
+ printf("%s,%d:\n", __func__, __LINE__);
+
+ for (i = 0; i < sizeof(dir_names_abs) / sizeof(char*); i++) {
+ using_scandir64_api(dir_names_abs[i]);
+ }
+
+ return ret_val;
+}
+
+int pfs_scandirat_test() {
+ uint32_t i;
+ int ret_val = 0;
+
+ const char* dir_names_abs[] = {
+ CLEAR_DIR_PATH, PROTECTED_DIR_PATH,
+ };
+
+ printf("%s,%d:\n", __func__, __LINE__);
+
+ for (i = 0; i < sizeof(dir_names_abs) / sizeof(char*); i++) {
+ using_scandirat_api(dir_names_abs[i]);
+ }
+
+ return ret_val;
+}
+
+int pfs_scandirat64_test() {
+ uint32_t i;
+ int ret_val = 0;
+
+ const char* dir_names_abs[] = {
+ CLEAR_DIR_PATH, PROTECTED_DIR_PATH,
+ };
+
+ printf("%s,%d:\n", __func__, __LINE__);
+
+ for (i = 0; i < sizeof(dir_names_abs) / sizeof(char*); i++) {
+ using_scandirat64_api(dir_names_abs[i]);
+ }
+
+ return ret_val;
+}
+
+int pfs_other_dirops_apis_test() {
+ uint32_t i;
+ int ret_val = 0;
+
+ const char* dir_names_abs[] = {
+ CLEAR_DIR_PATH, PROTECTED_DIR_PATH,
+ };
+
+ printf("%s,%d:\n", __func__, __LINE__);
+
+ for (i = 0; i < sizeof(dir_names_abs) / sizeof(char*); i++) {
+ using_other_dirops_apis(dir_names_abs[i]);
+ }
+
+ return ret_val;
+}
+
+int pfs_nftw_test() {
+ uint32_t i;
+ int ret_val = 0;
+
+ const char* dir_names_abs[] = {
+ /*CLEAR_DIR_PATH, */ PROTECTED_DIR_PATH,
+ };
+
+ printf("%s,%d:\n", __func__, __LINE__);
+
+ for (i = 0; i < sizeof(dir_names_abs) / sizeof(char*); i++) {
+ using_nftw_api(dir_names_abs[i]);
+ }
+
+ return ret_val;
+}
+
+int pfs_nftw64_test() {
+ uint32_t i;
+ int ret_val = 0;
+
+ const char* dir_names_abs[] = {
+ /*CLEAR_DIR_PATH, */ PROTECTED_DIR_PATH,
+ };
+
+ printf("%s,%d:\n", __func__, __LINE__);
+
+ for (i = 0; i < sizeof(dir_names_abs) / sizeof(char*); i++) {
+ using_nftw64_api(dir_names_abs[i]);
+ }
+
+ return ret_val;
+}
+
+int pfs_directory_system_apis_test() {
+ int overall_ret = 0;
+
+ overall_ret += pfs_readdir_test();
+ overall_ret += pfs_readdir64_test();
+ overall_ret += pfs_readdir_r_test();
+ overall_ret += pfs_readdir64_r_test();
+ overall_ret += pfs_scandir_test();
+ overall_ret += pfs_scandir64_test();
+ overall_ret += pfs_scandirat_test();
+ overall_ret += pfs_scandirat64_test();
+ overall_ret += pfs_other_dirops_apis_test();
+ overall_ret += pfs_nftw_test();
+ overall_ret += pfs_nftw64_test();
+
+ printf("\n#######%s, %s#######\n", __func__, ZERO_RESULT(overall_ret));
+
+ return overall_ret;
+}
diff --git a/pfs/apps/pfs_app/pfs_dirops.h b/pfs/apps/pfs_app/pfs_dirops.h
new file mode 100644
index 0000000..e2beafa
--- /dev/null
+++ b/pfs/apps/pfs_app/pfs_dirops.h
@@ -0,0 +1,51 @@
+/*
+ * License: BSD 3-Clause License
+ *
+ * Copyright (C) 2019 Intel Corporation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef _PFS_DIROPS_H_
+#define _PFS_DIROPS_H_
+
+int pfs_directory_system_apis_test();
+
+int pfs_readdir_test();
+int pfs_readdir64_test();
+int pfs_readdir_r_test();
+int pfs_readdir64_r_test();
+int pfs_scandir_test();
+int pfs_scandir64_test();
+int pfs_scandirat_test();
+int pfs_scandirat64_test();
+int pfs_nftw_test();
+int pfs_nftw64_test();
+int pfs_other_dirops_apis_test();
+
+#endif /* _PFS_DIROPS_H_ */
diff --git a/pfs/apps/pfs_app/pfs_fileops_apis.cpp b/pfs/apps/pfs_app/pfs_fileops_apis.cpp
new file mode 100644
index 0000000..848bc8f
--- /dev/null
+++ b/pfs/apps/pfs_app/pfs_fileops_apis.cpp
@@ -0,0 +1,1215 @@
+/*
+ * License: BSD 3-Clause "New" or "Revised" License
+ *
+ * Other web pages for this license
+ * http://www.opensource.org/licenses/BSD-3-Clause
+ *
+ * Copyright (C) 2019 Intel Corporation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "sgx_tseal.h"
+
+#include "dirops_typedefs.h"
+#include "fileops_typedefs.h"
+#include "pfs_debug.h"
+
+#include "perf_meas.h"
+#include "pfs_app.h"
+#include "pfs_dirops.h"
+
+char sprintf_buf_glb[SPRINTF_BUFSIZE];
+
+static int pfs_character_string_apis_test(FILE* sfp, file_type_t file_type);
+static int pfs_getc_ungetc_test(FILE* sfp, file_type_t file_type);
+
+static int pfs_file_offset_apis_test(const char* path_to_file, file_type_t file_type);
+static int pfs_secure_io_path_test();
+static int pfs_app_long_filename_test();
+static int system_apis_open_close(const char* filename, file_type);
+static int pfs_rename_test(const char* path_to_file, file_type_t file_type);
+
+static int invoke_vfscanf(FILE* stream, const char* format, ...);
+static int invoke_vfprintf(FILE* stream, const char* format, ...);
+static int test_vfscanf_vfprintf(FILE* stream, file_type_t file_type);
+
+static int pfs_getc_ungetc_test(FILE* sfp, file_type_t file_type) {
+ size_t file_len = 0;
+ uint8_t string_to_write[] = "Trial run";
+ int32_t ret_val = 0;
+
+ char byte_read;
+ char byte_from_ungetc;
+ long offset;
+ long offset_after_ungetc;
+
+ unsigned int i;
+ int overall_ret = 0;
+
+ if (!sfp) {
+ printf("\nDEBUG: Null pointer to %s", __func__);
+ return -1;
+ }
+
+ ret_val = fseek(sfp, 0L, SEEK_SET);
+
+ file_len = fwrite(string_to_write, sizeof(uint8_t), sizeof(string_to_write), sfp);
+
+ printf("DEBUG, after fwrite, file_len = %d\n", (int)file_len);
+
+ ret_val = fflush(sfp);
+
+ fseek(sfp, 0, SEEK_END);
+ file_len = (unsigned long)ftell(sfp);
+
+ ret_val = fseek(sfp, 0L, SEEK_SET);
+
+ printf("DEBUG, file_len = %lu\n", file_len);
+
+ for (i = 1; i <= file_len; i++) {
+ byte_read = getc(sfp);
+ offset = ftell(sfp);
+
+ if (byte_read == 'r') {
+ byte_from_ungetc = ungetc(byte_read, sfp);
+ offset_after_ungetc = ftell(sfp);
+
+ snprintf(sprintf_buf_glb, SPRINTF_BUFSIZE,
+ "byte_read=%c, byte_from_ungetc=%c. offset=%ld, offset_after_ungetc=%ld",
+ byte_read, byte_from_ungetc, offset, offset_after_ungetc);
+ overall_ret += check_bool_and_print_dbg(
+ "getc_ungetc", file_type,
+ ((byte_read == byte_from_ungetc) && ((offset_after_ungetc + 1) == offset)),
+ sprintf_buf_glb);
+
+ break;
+ }
+ }
+
+ return overall_ret;
+}
+
+// Note: Test works fine...
+static int pfs_character_string_apis_test(FILE* sfp, file_type_t file_type) {
+ int32_t ret_val = 0;
+ int overall_ret = 0;
+ uint8_t read_buffer[BUFFER_SIZE];
+
+ const char string_to_write[] = "Trial run";
+ const char test_string[] = "You said what";
+
+ int byte_read = 0;
+ int byte_written = 0;
+
+ uint64_t offset = 0;
+
+ if (!sfp) {
+ printf("\nDEBUG: invalid params to %s", __func__);
+ return -1;
+ }
+
+ memset(read_buffer, 0, sizeof(read_buffer));
+
+ ret_val = fseek(sfp, 0L, SEEK_SET);
+ // printf("DEBUG, after fseek, ret = %d\n", (int)ret_val);
+ overall_ret += check_bool_and_print_dbg("fseek", file_type, (ret_val == 0), (char*)"");
+
+ // Read from File
+ offset = ftell(sfp);
+ // printf("DEBUG: File offset = %lu\n", offset);
+ overall_ret += check_bool_and_print_dbg("ftell", file_type, (offset == 0), (char*)"");
+
+ byte_read = fgetc(sfp);
+ offset = ftell(sfp);
+
+ byte_written = putc(byte_read, sfp);
+ offset = ftell(sfp);
+
+ snprintf(sprintf_buf_glb, SPRINTF_BUFSIZE, "getc = %d, putc = %d", byte_read, byte_written);
+ overall_ret += check_bool_and_print_dbg("fgetc_putc", file_type, (byte_written == byte_read),
+ sprintf_buf_glb);
+
+ ret_val = fseek(sfp, 0L, SEEK_SET);
+ // printf("DEBUG, after fseek, ret = %d\n", (int)ret_val);
+
+ offset = ftell(sfp);
+ // printf("DEBUG: File offset = %lu\n", offset);
+
+ byte_read = fgetc(sfp);
+ offset = ftell(sfp);
+
+ byte_written = fputc(byte_read, sfp);
+ offset = ftell(sfp);
+
+ snprintf(sprintf_buf_glb, SPRINTF_BUFSIZE, "getc = %d, putc = %d", byte_read, byte_written);
+ overall_ret +=
+ check_bool_and_print_dbg("fgetc_fputc", file_type, (byte_written == byte_read), (char*)"");
+
+ ret_val = fseek(sfp, 0L, SEEK_SET);
+ // printf("DEBUG, after fseek, ret = %d\n", (int)ret_val);
+
+ if (sizeof(read_buffer) >= sizeof(string_to_write)) {
+ fgets((char*)read_buffer, sizeof(string_to_write), sfp);
+ }
+
+ ret_val = fseek(sfp, 0L, SEEK_SET);
+ // printf("DEBUG, after fseek, ret = %d\n", (int)ret_val);
+
+ ret_val = fputs((char*)test_string, sfp);
+ // printf("ret_val from fputs: %d\n", ret_val);
+
+ ret_val = fseek(sfp, 0L, SEEK_SET);
+ // printf("DEBUG, after fseek, ret = %d\n", (int)ret_val);
+
+ if (sizeof(read_buffer) >= sizeof(test_string)) {
+ fgets((char*)read_buffer, sizeof(test_string), sfp);
+ }
+
+ snprintf(sprintf_buf_glb, SPRINTF_BUFSIZE, "fgets = %s, fputs = %s", read_buffer, test_string);
+ overall_ret += check_bool_and_print_dbg(
+ "fputs_fgets", file_type,
+ (strncmp((const char*)read_buffer, test_string, strlen(test_string)) == 0), (char*)"");
+
+ overall_ret += pfs_getc_ungetc_test(sfp, file_type);
+
+ return overall_ret;
+}
+
+static int pfs_file_offset_apis_test(const char* path_to_file, file_type_t file_type) {
+ FILE* sfp = NULL;
+ uint8_t read_buffer[BUFFER_SIZE];
+ int32_t ret_val = 0;
+ int overall_ret = 0;
+
+ if (!path_to_file) {
+ printf("\nDEBUG: invalid params to %s", __func__);
+ return -1;
+ }
+
+ ret_val = open_file_wrapper(path_to_file, &sfp);
+
+ if (ret_val != 0) {
+ return ret_val;
+ }
+
+ memset(read_buffer, 0, sizeof(read_buffer));
+
+ ret_val = fseek(sfp, 0L, SEEK_SET);
+ // printf("DEBUG, after fseek, ret = %d\n", (int)ret_val);
+
+ // Read from File
+ int64_t file_offset = 0;
+ file_offset = ftell(sfp);
+ // printf("DEBUG: File offset = %lu\n", file_offset);
+
+ fpos_t position;
+
+ ret_val = fgetpos(sfp, &position);
+
+ overall_ret += check_ret_and_print_dbg("fgetpos", file_type, ret_val);
+
+ fputs("Hello, World!", sfp);
+
+ ret_val = fsetpos(sfp, &position);
+
+ overall_ret += check_ret_and_print_dbg("fsetpos", file_type, ret_val);
+
+ fputs("This is going to override previous content", sfp);
+
+ ret_val = fseeko(sfp, 0L, SEEK_SET);
+ // printf("DEBUG, after fseeko, ret = %d\n", (int)ret_val);
+ overall_ret += check_bool_and_print_dbg("fseeko", file_type, (ret_val == 0), (char*)"");
+
+ // Read from File
+ file_offset = ftello(sfp);
+ // printf("DEBUG: File offset = %ld\n", file_offset);
+ overall_ret += check_bool_and_print_dbg("ftello", file_type, (file_offset == 0), (char*)"");
+
+ ret_val = fclose(sfp);
+
+ // printf("DEBUG, after fclose, ret_val = %d\n", (int)ret_val);
+
+ return overall_ret;
+}
+
+static int pfs_secure_io_path_test() {
+ FILE* fp = NULL;
+ unsigned int i;
+ int ret_val = 0;
+ int overall_ret = 0;
+
+ const char* file_names[] = {"/pfs_dir/non_secrets/temp100", "/pfs_dir/secrets/temp100"};
+
+ const char* file_names_rel[] = {"../non_secrets/temp101", "../secrets/temp101"};
+
+ const char* file_names_invalid[] = {"../non_sec/temp101", "/pfs_dir/sec/temp100"};
+
+ for (i = 0; i < sizeof(file_names) / sizeof(char*); i++) {
+ fp = fopen(file_names[i], "w+");
+
+ snprintf(sprintf_buf_glb, SPRINTF_BUFSIZE, "filepath=%s", file_names[i]);
+
+ overall_ret +=
+ check_bool_and_print_dbg("fopen", NOT_APPLICABLE, (fp != NULL), (char*)sprintf_buf_glb);
+
+ if (fp) {
+ fclose(fp);
+ fp = NULL;
+ }
+ }
+
+ ret_val = chdir(TEST_DIR_PATH);
+
+ if (ret_val != 0) {
+ printf("chdir to %s, returned error, ret_val=%d, errno=%d\n", TEST_DIR_PATH, ret_val,
+ errno);
+ overall_ret += -1;
+ goto exit;
+ }
+
+ for (i = 0; i < sizeof(file_names_rel) / sizeof(char*); i++) {
+ fp = fopen(file_names_rel[i], "w+");
+
+ snprintf(sprintf_buf_glb, SPRINTF_BUFSIZE, "filepath=%s", file_names_rel[i]);
+
+ overall_ret +=
+ check_bool_and_print_dbg("fopen", NOT_APPLICABLE, (fp != NULL), (char*)sprintf_buf_glb);
+
+ if (fp) {
+ fclose(fp);
+ fp = NULL;
+ }
+ }
+
+ for (i = 0; i < sizeof(file_names_invalid) / sizeof(char*); i++) {
+ fp = fopen(file_names_invalid[i], "r");
+
+ snprintf(sprintf_buf_glb, SPRINTF_BUFSIZE, "filepath=%s", file_names_invalid[i]);
+
+ overall_ret +=
+ check_bool_and_print_dbg("fopen", NOT_APPLICABLE, (fp == NULL), (char*)sprintf_buf_glb);
+
+ if (fp) {
+ fclose(fp);
+ fp = NULL;
+ }
+ }
+
+exit:
+
+ printf("%s, %d: ret_val->%d\n", __func__, __LINE__, overall_ret);
+
+ return overall_ret;
+}
+
+// Note: Test API for low-level system apis that use file-descriptor
+// like open/close..to ensure it works fine for normal files(i.e. non-protected files).
+static int system_apis_open_close(const char* filename, file_type_t file_type) {
+ int ret = 0;
+ int overall_ret = 0;
+ int fd = -1;
+ mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
+ ssize_t len = 0;
+ uint8_t string_to_write[] = "^^Low-level-APIs->Trial run^^";
+
+ if (filename == NULL || strnlen(filename, 1) == 0) {
+ printf("filename is NULL or empty\n");
+ return -1;
+ }
+
+ // create the file if it doesn't exists, read-only/read-write
+ fd = open(filename, O_CREAT | O_RDWR | O_APPEND, mode);
+
+ overall_ret += check_fd_and_print_dbg("open", file_type, fd);
+
+ len = write(fd, string_to_write, sizeof(string_to_write));
+
+ overall_ret += check_bool_and_print_dbg(
+ "write", file_type, ((file_type == NORMAL && (len == sizeof(string_to_write))) ||
+ (file_type == PROTECTED && len == -1)),
+ (char*)"");
+
+ ret = close(fd);
+ overall_ret += check_ret_and_print_dbg("close", file_type, ret);
+
+ return overall_ret;
+}
+
+static int pfs_app_long_filename_test() {
+ int ret = 0;
+ int overall_ret = 0;
+ char filename[FILENAME_MAX_LENGTH];
+ char* file_path = NULL;
+ uint32_t cnt = 0;
+ FILE* fp = NULL;
+
+ memset(filename, 0, sizeof(filename));
+
+ for (cnt = 0; cnt < sizeof(filename) - 1; cnt++) {
+ filename[cnt] = 'a';
+ }
+
+ file_path = (char*)calloc(strlen(CLEAR_DIR_PATH) + 1 + sizeof(filename) + 1, 1);
+
+ if (file_path != NULL) {
+ strncpy(file_path, CLEAR_DIR_PATH, strlen(CLEAR_DIR_PATH));
+ file_path[strlen(CLEAR_DIR_PATH)] = '/';
+ strncpy(file_path + strlen(CLEAR_DIR_PATH) + 1, filename, strlen(filename));
+
+ // printf("filename=%s, strlen(filename)=%lu\n", filename, strlen(filename));
+ // printf("file-path=%s, strlen(file-path)=%lu\n", file_path, strlen(file_path));
+
+ fp = fopen((const char*)file_path, "wb+");
+
+ snprintf(sprintf_buf_glb, SPRINTF_BUFSIZE, "filepath=%s", file_path);
+
+ overall_ret +=
+ check_bool_and_print_dbg("fopen", NOT_APPLICABLE, (fp != NULL), (char*)sprintf_buf_glb);
+
+ if (fp) {
+ ret = fclose(fp);
+ ret = remove(file_path);
+ }
+ }
+
+ if (file_path) {
+ free(file_path);
+ }
+
+ return overall_ret;
+}
+
+static int pfs_rename_test(const char* path_to_file, file_type_t file_type) {
+ int overall_ret = 0;
+ int rename_ret = 0;
+ const char rename_suffix[] = "_rename";
+ char* renamed_path = NULL;
+
+ renamed_path =
+ (char*)calloc((strlen(path_to_file) + strlen(rename_suffix) + 1), sizeof(uint8_t));
+
+ if (!renamed_path) {
+ printf("malloc failed");
+ return -1;
+ }
+
+ strncpy(renamed_path, path_to_file, strlen(path_to_file));
+
+ renamed_path =
+ strncat(renamed_path, (const char*)rename_suffix, strlen((const char*)rename_suffix));
+
+ printf("path to rename to=%s\n", renamed_path);
+
+ rename_ret = rename(path_to_file, renamed_path);
+
+ overall_ret += check_ret_and_print_dbg("rename", file_type, rename_ret);
+
+ /*Note: issue https://github.com/oscarlab/graphene/pull/911/
+ * rename has been resolved in latest version of graphene.*/
+ if (rename_ret == 0) {
+ rename_ret = rename(renamed_path, path_to_file);
+
+ snprintf(sprintf_buf_glb, SPRINTF_BUFSIZE,
+ "undoing of rename, old path=%s, new path=%s, ret_val=%d", path_to_file,
+ renamed_path, rename_ret);
+ overall_ret += check_bool_and_print_dbg("rename", file_type,
+ ((file_type == NORMAL && rename_ret == 0) ||
+ (file_type == PROTECTED && rename_ret == -1)),
+ sprintf_buf_glb);
+ }
+
+ rename_ret = renameat(AT_FDCWD, path_to_file, AT_FDCWD, renamed_path);
+
+ overall_ret += check_bool_and_print_dbg(
+ "renameat", file_type,
+ ((file_type == NORMAL && rename_ret == -1) || (file_type == PROTECTED && rename_ret == -1)),
+ "");
+
+ if (rename_ret == 0) {
+ rename_ret = renameat(AT_FDCWD, renamed_path, AT_FDCWD, path_to_file);
+
+ snprintf(sprintf_buf_glb, SPRINTF_BUFSIZE,
+ "undoing of renameat, old path=%s, new path=%s, ret_val=%d", path_to_file,
+ renamed_path, rename_ret);
+ overall_ret += check_bool_and_print_dbg("rename", file_type,
+ ((file_type == NORMAL && rename_ret == 0) ||
+ (file_type == PROTECTED && rename_ret == -1)),
+ sprintf_buf_glb);
+ }
+
+ if (renamed_path)
+ free(renamed_path);
+
+ return overall_ret;
+}
+
+static int invoke_vfscanf(FILE* stream, const char* format, ...) {
+ int ret = 0;
+ va_list args;
+ va_start(args, format);
+ ret = vfscanf(stream, format, args);
+
+ va_end(args);
+
+ return ret;
+}
+
+static int invoke_vfprintf(FILE* stream, const char* format, ...) {
+ int ret = 0;
+
+ va_list args;
+ va_start(args, format);
+ ret = vfprintf(stream, format, args);
+
+ va_end(args);
+
+ return ret;
+}
+
+static int test_vfscanf_vfprintf(FILE* sfp, file_type_t file_type) {
+ int ret_val = 0;
+ bool result = 0;
+ char test_string[100];
+ int overall_ret = 0;
+
+ if (!sfp)
+ return -1;
+
+ errno = 0;
+
+ ret_val = invoke_vfscanf(sfp, "%ls", test_string);
+
+ result = 0;
+ if ((file_type == NORMAL /*&& errno == 0*/) || (file_type == PROTECTED && ret_val == -1)) {
+ result = 1;
+ }
+ snprintf(sprintf_buf_glb, SPRINTF_BUFSIZE, "vfscanf's ret = %d, errno=%d", ret_val, errno);
+
+ overall_ret += check_bool_and_print_dbg("vfscanf", file_type, result, (char*)sprintf_buf_glb);
+
+ ret_val = invoke_vfprintf(sfp, "String with variable %ls.\n", "arguments");
+
+ result = 0;
+ if ((file_type == NORMAL /*&& errno == 0*/) || (file_type == PROTECTED && ret_val == -1)) {
+ result = 1;
+ }
+ snprintf(sprintf_buf_glb, SPRINTF_BUFSIZE, "vfprintf's ret = %d, errno=%d", ret_val, errno);
+
+ overall_ret += check_bool_and_print_dbg("vfprintf", file_type, result, (char*)"");
+
+ return overall_ret;
+}
+
+int check_ret_and_print_dbg(const char* func, file_type_t file_type, int ret_val) {
+ int ret = 0;
+ bool result = 0;
+
+ if (!func)
+ return -1;
+
+ if (file_type == PROTECTED) {
+ result = (ret_val == -1) ? 1 : 0;
+
+ printf("\n%s, %s, file_type=%s, ret_val=%d, errno=%d\n", func, EXPECTED_TRUE(result),
+ "PROTECTED", ret_val, errno);
+ } else {
+ result = (ret_val == 0) ? 1 : 0;
+
+ printf("\n%s, %s, file_type=%s, ret_val=%d, errno=%d\n", func, EXPECTED_TRUE(result),
+ "NORMAL", ret_val, errno);
+ }
+
+ // Note: Helps to verify that over-riding apis set the correct errno
+ errno = 0;
+
+ return (ret | !result);
+}
+
+int check_ptr_and_print_dbg(const char* func, file_type_t file_type, void* ptr) {
+ int ret = 0;
+ bool result = 0;
+
+ if (!func)
+ return -1;
+
+ if (file_type == PROTECTED) {
+ result = (ptr == NULL) ? 1 : 0;
+
+ printf("\n%s, %s, file_type=%s, ptr=%p, errno=%d\n", func, EXPECTED_TRUE(result),
+ "PROTECTED", ptr, errno);
+ } else {
+ result = (ptr != NULL) ? 1 : 0;
+
+ printf("\n%s, %s, file_type=%s, ptr=%p, errno=%d\n", func, EXPECTED_TRUE(result), "NORMAL",
+ ptr, errno);
+ }
+
+ // Note: Helps to verify that over-riding apis set the correct errno
+ errno = 0;
+
+ return (ret | !result);
+}
+
+int check_fd_and_print_dbg(const char* func, file_type_t file_type, int fd) {
+ int ret = 0;
+ bool result = 0;
+
+ if (!func)
+ return -1;
+
+ if (file_type == PROTECTED) {
+ result = (fd == -1) ? 1 : 0;
+
+ printf("\n%s, %s, file_type=%s, fd=%d, errno=%d\n", func, EXPECTED_TRUE(result),
+ "PROTECTED", fd, errno);
+ } else {
+ result = (fd > 0) ? 1 : 0;
+
+ printf("\n%s, %s, file_type=%s, fd=%d, errno=%d\n", func, EXPECTED_TRUE(result), "NORMAL",
+ fd, errno);
+ }
+
+ // Note: Helps to verify that over-riding apis set the correct errno
+ errno = 0;
+
+ return (ret | !result);
+}
+
+int check_errno_and_print_dbg(const char* func, file_type_t file_type, wint_t ret_val) {
+ int ret = 0;
+ bool result = 0;
+
+ if (!func)
+ return -1;
+
+ if (file_type == PROTECTED) {
+ result = (errno == ENOTSUP) ? 1 : 0;
+
+ printf("\n%s, %s, file_type=%s, errno=%d, ret_val=%d\n", func, EXPECTED_TRUE(result),
+ "PROTECTED", errno, ret_val);
+ } else {
+ result = (errno == 0) ? 1 : 0;
+
+ printf("\n%s, %s, file_type=%s, errno=%d, ret_val=%d\n", func, EXPECTED_TRUE(result),
+ "NORMAL", errno, ret_val);
+ }
+
+ // Note: Helps to verify that over-riding apis set the correct errno
+ errno = 0;
+
+ return (ret | !result);
+}
+
+int check_bool_and_print_dbg(const char* func, file_type_t file_type, bool result, char* dbg_str) {
+ int ret = 0;
+
+ if (!func)
+ return -1;
+
+ printf("\n%s, %s, file_type=%s, errno=%d, dbg_str->%s\n", func, EXPECTED_TRUE(result),
+ (file_type == PROTECTED) ? "PROTECTED"
+ : ((file_type == NORMAL) ? "NORMAL" : "NOT_APPLICABLE"),
+ errno, dbg_str);
+
+ // Note: Helps to verify that over-riding apis set the correct errno
+ errno = 0;
+
+ return (ret | !result);
+}
+
+int open_file_wrapper(const char* path_to_file, FILE** fp) {
+ int ret = 0;
+ FILE* sfp = NULL;
+
+ if (!path_to_file || !fp)
+ return -1;
+
+ printf("\nsizeof(path)=%lu, file-name=%s\n", strlen(path_to_file), path_to_file);
+
+ sfp = fopen((const char*)path_to_file, "rb");
+
+ if (sfp == NULL) {
+ printf("DEBUG, creating new testfile in wb+ mode \n");
+
+ sfp = fopen((const char*)path_to_file, "wb+");
+ } else {
+ fclose(sfp);
+ // Note: changed mode from ab+ to wb+ to shorten
+ // debug output of file content, to ease debugging.
+ /*printf("DEBUG, opening existing file in ab+ mode\n");
+ sfp = fopen((const char*)path_to_file, "ab+");*/
+ printf("DEBUG, opening existing file in wb+ mode\n");
+ sfp = fopen((const char*)path_to_file, "wb+");
+ }
+
+ if (!sfp) {
+ printf("DEBUG, %s:%d, error sfp=%p is NULL\n", __func__, __LINE__, sfp);
+ return -1;
+ } else {
+ *fp = sfp;
+ }
+
+ return ret;
+}
+
+int create_test_file(const char* path_to_file) {
+ FILE* sfp = NULL;
+ size_t buffer_len = 0;
+ uint8_t string_to_write[] = "Trial run";
+ int32_t ret_val = 0;
+
+ if (!path_to_file) {
+ printf("\nDEBUG: invalid params to %s", __func__);
+ return -1;
+ }
+
+ ret_val = open_file_wrapper(path_to_file, &sfp);
+
+ if (ret_val != 0) {
+ return ret_val;
+ }
+
+ buffer_len = fwrite(string_to_write, sizeof(uint8_t), sizeof(string_to_write), sfp);
+ // printf("DEBUG, after fwrite, buffer_len = %d\n", (int)buffer_len);
+
+ ret_val = fclose(sfp);
+ // printf("DEBUG, after fclose, ret_val = %d\n", (int)ret_val);
+
+ return ret_val;
+}
+
+// Note: Test works fine...
+int test_for_apis_supported_for_protected_files(const char* path_to_file, file_type_t file_type) {
+ FILE* sfp = NULL;
+ size_t buffer_len = 0;
+ uint8_t string_to_write[] = "Trial run";
+ uint8_t read_buffer[BUFFER_SIZE];
+ int32_t ret_val = 0;
+ int overall_ret = 0;
+
+ bool result = 0;
+ errno = 0;
+
+ if (!path_to_file) {
+ printf("\nDEBUG: invalid params to %s", __func__);
+ return -1;
+ }
+
+ ret_val = open_file_wrapper(path_to_file, &sfp);
+
+ if (ret_val != 0) {
+ return ret_val;
+ }
+
+ buffer_len = fwrite(string_to_write, sizeof(uint8_t), sizeof(string_to_write), sfp);
+
+ overall_ret += check_bool_and_print_dbg("fwrite", file_type,
+ (buffer_len == sizeof(string_to_write)), (char*)"");
+
+ ret_val = fflush(sfp);
+
+ overall_ret += check_bool_and_print_dbg("fflush", file_type, (ret_val == 0), (char*)"");
+
+ ret_val = ferror(sfp);
+
+ printf("DEBUG, after ferror, ret_val = %d\n", (int)ret_val);
+
+ memset(read_buffer, 0, sizeof(read_buffer));
+
+ /*Note: Application needs to do a seek to reset
+ the file offset to the start of the file, i.e if it tries
+ to do a file read, after doing a write */
+ ret_val = fseek(sfp, 0L, SEEK_SET);
+
+ overall_ret += check_bool_and_print_dbg("fseek", file_type, (ret_val == 0), (char*)"");
+
+ buffer_len = fread(read_buffer, sizeof(uint8_t), sizeof(read_buffer), sfp);
+ // printf("DEBUG, after fread, file_len = %d\n", (int)buffer_len);
+
+ overall_ret += check_bool_and_print_dbg("fread", file_type, (buffer_len > 0), (char*)"");
+
+ // Read from File
+ uint64_t file_offset = 0;
+ file_offset = ftell(sfp);
+ // printf("DEBUG: File offset = %lu\n", file_offset);
+
+ overall_ret += check_bool_and_print_dbg("ftell", file_type, (file_offset != -1), (char*)"");
+
+ printf("DEBUG: Stuff fread from file byte output\n");
+
+ for (unsigned int cnt = 0; cnt < buffer_len; cnt++) {
+ printf("%c", read_buffer[cnt]);
+ if (!((cnt + 1) % 12))
+ printf("\n");
+ }
+
+ ret_val = feof(sfp);
+ overall_ret += check_bool_and_print_dbg("feof", file_type, (ret_val != -1), (char*)"");
+
+ clearerr(sfp);
+
+ ret_val = feof(sfp);
+
+ // printf("DEBUG, after feof, ret_val = %d\n", (int)ret_val);
+
+ overall_ret += pfs_character_string_apis_test(sfp, file_type);
+
+ ret_val = fclose(sfp);
+ overall_ret += check_bool_and_print_dbg("fclose", file_type, (ret_val != -1), (char*)"");
+
+ errno = 0;
+ ret_val = remove(path_to_file);
+ overall_ret += check_bool_and_print_dbg("remove", file_type, (ret_val == 0), (char*)"");
+
+ printf("MOUNT_POINT : %s\n", getenv("PFS_MOUNT_POINT"));
+
+ printf("\n#######%s, file_type=%s, %s#######\n", __func__, FILE_TYPE_STRING(file_type),
+ ZERO_RESULT(overall_ret));
+
+ return overall_ret;
+}
+
+// Note: Test works fine...except for issues commented below.
+int test_for_apis_unsupported_for_protected_files(const char* path_to_file, file_type_t file_type) {
+ FILE* sfp = NULL;
+ FILE* fp = NULL;
+ int fd = 0;
+ int overall_ret = 0;
+ int val = 0;
+
+ uint8_t read_buffer[BUFFER_SIZE];
+ int32_t ret_val = 0;
+
+ uint8_t test_string[] = "You said what";
+
+ if (!path_to_file) {
+ printf("\nDEBUG: invalid params to %s", __func__);
+ return -1;
+ }
+
+ errno = 0;
+
+ ret_val = open_file_wrapper(path_to_file, &sfp);
+
+ if (ret_val != 0) {
+ return ret_val;
+ }
+
+ memset(read_buffer, 0, sizeof(read_buffer));
+
+ ret_val = fseek(sfp, 0L, SEEK_SET);
+ // printf("DEBUG, after fseek, ret = %d\n", (int)ret_val);
+
+ // Read from File
+ uint64_t file_offset = 0;
+ file_offset = ftell(sfp);
+ printf("DEBUG: File offset = %lu\n", file_offset);
+
+ fd = fileno(sfp);
+
+ overall_ret += check_fd_and_print_dbg("fileno", file_type, fd);
+
+ fp = freopen(path_to_file, "rw+", sfp);
+
+ overall_ret += check_ptr_and_print_dbg("freopen", file_type, (void*)fp);
+
+ if (fp != NULL) {
+ /* As per man-page, after successful freopen, the previous
+ * stream is closed, so should be using the old stream pointer */
+ sfp = fp;
+ }
+
+ fpos_t position;
+
+ ret_val = fgetpos(sfp, &position);
+
+ overall_ret += check_ret_and_print_dbg("fgetpos", file_type, ret_val);
+
+ ret_val = fsetpos(sfp, &position);
+
+ overall_ret += check_ret_and_print_dbg("fsetpos", file_type, ret_val);
+
+ /*// Note: add test code below...keeping it commented..for reference...
+ if (file_type == NORMAL) {
+ wchar_t wide_str[100];
+
+ ret_val = fprintf(stdout, "fprintf-PRINT TO STDOUT\n");
+ printf("\nafter fprintf, ret_val=%d, errno=%d\n", ret_val, errno);
+
+ ret_val = fwprintf(stdout, L"fwprintf-PRINT TO STDOUT\n");
+ printf("\nafter fwprintf, ret_val=%d, errno=%d\n", ret_val, errno);
+
+ ret_val = fscanf(stdin, "%d", &val);
+ printf("\nafter fscanf, ret_val=%d, errno=%d\n", ret_val, errno);
+
+ ret_val = fwscanf(stdin, L" %ls", wide_str);
+ printf("\nafter fwscanf, ret_val=%d, errno=%d\n", ret_val, errno);
+ }*/
+
+ ret_val = fprintf(sfp, "%d", val);
+
+ snprintf(sprintf_buf_glb, SPRINTF_BUFSIZE, "fprintf's ret = %d, errno=%d", ret_val, errno);
+ overall_ret += check_bool_and_print_dbg(
+ "fprintf", file_type,
+ ((file_type == NORMAL && errno == 0) || (file_type == PROTECTED && ret_val == -1)),
+ (char*)sprintf_buf_glb);
+
+ ret_val = fscanf(sfp, "%d", &val);
+ snprintf(sprintf_buf_glb, SPRINTF_BUFSIZE, "fscanf's ret = %d, errno=%d", ret_val, errno);
+ overall_ret += check_bool_and_print_dbg(
+ "fscanf", file_type,
+ ((file_type == NORMAL && errno == 0) || (file_type == PROTECTED && ret_val == -1)),
+ (char*)sprintf_buf_glb);
+
+ ret_val = fwprintf(sfp, L"wide-char string\n");
+ snprintf(sprintf_buf_glb, SPRINTF_BUFSIZE, "fwprintf's ret = %d, errno=%d", ret_val, errno);
+
+ overall_ret += check_bool_and_print_dbg(
+ "fwprintf", file_type,
+ ((file_type == NORMAL && errno == 0) || (file_type == PROTECTED && ret_val == -1)),
+ (char*)sprintf_buf_glb);
+
+ ret_val = fwscanf(sfp, (wchar_t*)"%d", &val);
+ snprintf(sprintf_buf_glb, SPRINTF_BUFSIZE, "fwscanf's ret = %d, errno=%d", ret_val, errno);
+
+ overall_ret += check_bool_and_print_dbg(
+ "fwscanf", file_type,
+ ((file_type == NORMAL && errno == 0) || (file_type == PROTECTED && ret_val == -1)),
+ (char*)fwscanf);
+
+ setbuf(sfp, (char*)test_string);
+ overall_ret += check_errno_and_print_dbg("setbuf", file_type, 0);
+
+ setbuffer(sfp, (char*)test_string, sizeof(test_string));
+ overall_ret += check_errno_and_print_dbg("setbuffer", file_type, 0);
+
+ setlinebuf(sfp);
+ overall_ret += check_errno_and_print_dbg("setlinebuf", file_type, 0);
+
+ ret_val = setvbuf(sfp, (char*)test_string, _IONBF, sizeof(test_string));
+ overall_ret += check_ret_and_print_dbg("setvbuf", file_type, ret_val);
+
+ ret_val = fclose(sfp);
+
+ overall_ret += pfs_rename_test(path_to_file, file_type);
+
+ overall_ret += test_vfscanf_vfprintf(sfp, file_type);
+
+ printf("\n#######%s, file_type=%s, %s#######\n", __func__, FILE_TYPE_STRING(file_type),
+ ZERO_RESULT(overall_ret));
+
+ return overall_ret;
+}
+
+// Note: Test works fine...
+int test_for_blocking_apis_that_return_file_descriptor(const char* path_to_file,
+ file_type_t file_type) {
+ int ret = 0;
+ int overall_ret = 0;
+ int fd;
+
+ int flags = O_CREAT;
+
+ mode_t mode = S_IRWXU | S_IRGRP | S_IROTH;
+
+ errno = 0;
+
+ fd = creat(path_to_file, mode);
+
+ overall_ret += check_fd_and_print_dbg("creat", file_type, fd);
+
+ ret = close(fd);
+
+ overall_ret += check_ret_and_print_dbg("close", file_type, ret);
+
+ fd = open(path_to_file, flags, mode);
+
+ overall_ret += check_fd_and_print_dbg("open", file_type, fd);
+
+ ret = close(fd);
+
+ overall_ret += check_ret_and_print_dbg("close", file_type, ret);
+
+ flags = O_RDWR;
+
+ fd = open(path_to_file, flags);
+
+ // printf("fd=%d, after open without mode\n", fd);
+ overall_ret += check_fd_and_print_dbg("open", file_type, fd);
+
+ ret = close(fd);
+
+ overall_ret += check_ret_and_print_dbg("close", file_type, ret);
+
+ fd = open(path_to_file, O_TMPFILE | O_RDWR, mode);
+
+ // printf("fd=%d, after open using O_TMPFILE\n", fd);
+ overall_ret += check_fd_and_print_dbg("open", file_type, fd);
+
+ close(fd);
+
+ flags = O_CREAT;
+
+ fd = openat(0, path_to_file, flags, mode);
+
+ // printf("fd=%d, after openat\n", fd);
+ overall_ret += check_fd_and_print_dbg("openat", file_type, fd);
+
+ flags = O_RDWR;
+
+ fd = openat(0, path_to_file, flags);
+
+ // printf("fd=%d, after openat without mode\n", fd);
+ overall_ret += check_fd_and_print_dbg("openat", file_type, fd);
+
+ close(fd);
+
+ printf("\n#######%s, file_type=%s, %s#######\n", __func__, FILE_TYPE_STRING(file_type),
+ ZERO_RESULT(overall_ret));
+
+ return overall_ret;
+}
+
+int test_for_misc_test_cases1(const char* path_to_file, file_type_t file_type) {
+ int overall_ret = 0;
+
+ errno = 0;
+
+ overall_ret += pfs_file_offset_apis_test(path_to_file, file_type);
+ overall_ret += system_apis_open_close(path_to_file, file_type);
+
+ printf("\n#######%s, file_type=%s, %s#######\n", __func__, FILE_TYPE_STRING(file_type),
+ ZERO_RESULT(overall_ret));
+
+ return overall_ret;
+}
+
+int test_for_misc_test_cases2() {
+ int overall_ret = 0;
+
+ errno = 0;
+
+ overall_ret += pfs_secure_io_path_test();
+ overall_ret += pfs_app_long_filename_test();
+
+ printf("\n#######%s, %s#######\n", __func__, ZERO_RESULT(overall_ret));
+
+ return overall_ret;
+}
+
+static int open_file_wrapper_64bit(const char* path_to_file, FILE** fp) {
+ int ret = 0;
+ FILE* sfp = NULL;
+
+ if (!path_to_file || !fp)
+ return -1;
+
+ printf("sizeof(path)=%lu, file-name=%s\n", strlen(path_to_file), path_to_file);
+
+ sfp = fopen64((const char*)path_to_file, "rb+");
+
+ if (sfp == NULL) {
+ printf("DEBUG, creating new testfile in wb+ mode \n");
+
+ sfp = fopen64((const char*)path_to_file, "w+b");
+ } else {
+ fclose(sfp);
+ printf("DEBUG, opening existing file in ab+ mode\n");
+
+ sfp = fopen64((const char*)path_to_file, "a+b");
+ }
+
+ if (!sfp) {
+ printf("DEBUG, %s:%d, error sfp=%p is NULL\n", __func__, __LINE__, sfp);
+ return -1;
+ } else {
+ *fp = sfp;
+ }
+
+ return ret;
+}
+
+static int blocking_64bit_apis_that_return_file_descriptor(const char* path_to_file,
+ file_type_t file_type) {
+ int ret_val = 0;
+ int overall_ret = 0;
+
+ int fd;
+
+ int flags = O_CREAT;
+
+ mode_t mode = S_IRWXU | S_IRGRP | S_IROTH;
+
+ fd = creat64(path_to_file, mode);
+
+ overall_ret += check_fd_and_print_dbg("creat64", file_type, fd);
+
+ close(fd);
+
+ fd = open64(path_to_file, flags, mode);
+
+ overall_ret += check_fd_and_print_dbg("open64", file_type, fd);
+
+ ret_val = close(fd);
+
+ overall_ret += check_ret_and_print_dbg("close", file_type, ret_val);
+
+ flags = O_RDWR;
+
+ // open without mode
+ fd = open64(path_to_file, flags);
+
+ overall_ret += check_fd_and_print_dbg("open64", file_type, fd);
+
+ ret_val = close(fd);
+
+ overall_ret += check_ret_and_print_dbg("close", file_type, ret_val);
+
+ // open using O_TMPFILE
+ fd = open64(path_to_file, O_TMPFILE | O_RDWR, mode);
+
+ overall_ret += check_fd_and_print_dbg("open64", file_type, fd);
+
+ close(fd);
+
+ flags = O_CREAT;
+
+ fd = openat64(0, path_to_file, flags, mode);
+
+ overall_ret += check_fd_and_print_dbg("openat64", file_type, fd);
+
+ flags = O_RDWR;
+
+ // openat without mode
+ fd = openat64(0, path_to_file, flags);
+
+ overall_ret += check_fd_and_print_dbg("openat64", file_type, fd);
+
+ close(fd);
+
+ return overall_ret;
+}
+
+static int pfs_override_test_64bit(const char* path_to_file, file_type_t file_type) {
+ FILE* sfp = NULL;
+ size_t buffer_len = 0;
+ uint8_t string_to_write[] = "Trial run";
+ uint8_t read_buffer[BUFFER_SIZE];
+ int32_t ret_val = 0;
+ int overall_ret = 0;
+
+ if (!path_to_file) {
+ printf("\nDEBUG: invalid params to %s", __func__);
+ return -1;
+ }
+
+ ret_val = open_file_wrapper_64bit(path_to_file, &sfp);
+
+ if (ret_val != 0) {
+ return ret_val;
+ }
+
+ buffer_len = fwrite(string_to_write, sizeof(uint8_t), sizeof(string_to_write), sfp);
+ printf("DEBUG, after fwrite, buffer_len = %d\n", (int)buffer_len);
+
+ ret_val = fflush(sfp);
+ printf("DEBUG, after fflush, ret_val = %d\n", (int)ret_val);
+
+ memset(read_buffer, 0, sizeof(read_buffer));
+
+ ret_val = fseeko64(sfp, 0L, SEEK_SET);
+ printf("DEBUG, after fseek, ret = %d\n", (int)ret_val);
+
+ buffer_len = fread(read_buffer, sizeof(uint8_t), sizeof(read_buffer), sfp);
+ printf("DEBUG, after fread, file_len = %d\n", (int)buffer_len);
+
+ // Read from File
+ uint64_t file_offset = 0;
+ file_offset = ftello64(sfp);
+ printf("DEBUG: File offset = %lu\n", file_offset);
+
+ printf("DEBUG: Stuff fread from file byte output\n");
+
+ for (unsigned int cnt = 0; cnt < buffer_len; cnt++) {
+ printf("%c", read_buffer[cnt]);
+ if (!((cnt + 1) % 12))
+ printf("\n");
+ }
+
+ fpos64_t position;
+ FILE* new_fp = NULL;
+
+ ret_val = fgetpos64(sfp, &position);
+
+ overall_ret += check_ret_and_print_dbg("fgetpos64", file_type, ret_val);
+
+ fputs("Hello, World!", sfp);
+
+ ret_val = fsetpos64(sfp, &position);
+
+ overall_ret += check_ret_and_print_dbg("fsetpos64", file_type, ret_val);
+
+ // If filename is NOT specified..it will close the original
+ // file and re-open with the new mode.
+ new_fp = freopen64("", "rw+", sfp);
+
+ overall_ret += check_ptr_and_print_dbg("freopen64", file_type, (void*)new_fp);
+
+ fclose(sfp);
+
+ return overall_ret;
+}
+
+int test_for_64bit_apis(const char* path_to_file, file_type_t file_type) {
+ int overall_ret = 0;
+
+ errno = 0;
+
+ overall_ret += pfs_override_test_64bit(path_to_file, file_type);
+ overall_ret += blocking_64bit_apis_that_return_file_descriptor(path_to_file, file_type);
+
+ printf("\n#######%s, file_type=%s, %s#######\n", __func__, FILE_TYPE_STRING(file_type),
+ ZERO_RESULT(overall_ret));
+
+ return overall_ret;
+}
diff --git a/pfs/apps/pfs_app/pfs_wide_char_apis.cpp b/pfs/apps/pfs_app/pfs_wide_char_apis.cpp
new file mode 100644
index 0000000..d4f70f7
--- /dev/null
+++ b/pfs/apps/pfs_app/pfs_wide_char_apis.cpp
@@ -0,0 +1,169 @@
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+
+#include "pfs_debug.h"
+
+#include "perf_meas.h"
+#include "pfs_app.h"
+#include "pfs_dirops.h"
+
+extern char sprintf_buf_glb[SPRINTF_BUFSIZE];
+
+static int wide_format_vfwscanf(FILE* stream, const wchar_t* format, ...) {
+ int ret = 0;
+ va_list args;
+ va_start(args, format);
+ ret = vfwscanf(stream, format, args);
+
+ va_end(args);
+
+ return ret;
+}
+
+static int wide_format_vfwprintf(FILE* stream, const wchar_t* format, ...) {
+ int ret = 0;
+
+ va_list args;
+ va_start(args, format);
+ ret = vfwprintf(stream, format, args);
+
+ va_end(args);
+
+ return ret;
+}
+
+int test_for_wide_char_apis_unsupported(const char* path_to_file, file_type_t file_type) {
+ FILE* sfp = NULL;
+ int ret_val = 0;
+
+ wint_t wc;
+ wint_t wc2;
+ wchar_t test_string[100];
+ wchar_t* ret_str = NULL;
+
+ bool result = 0;
+ int overall_ret = 0;
+
+ errno = 0;
+
+ if (!path_to_file) {
+ printf("\nDEBUG: invalid params to %s", __func__);
+ return -1;
+ }
+
+ ret_val = open_file_wrapper(path_to_file, &sfp);
+
+ if (ret_val != 0) {
+ return ret_val;
+ }
+
+ fputs("Hello World\n", sfp);
+
+ fclose(sfp);
+
+ sfp = fopen(path_to_file, "ab+");
+ if (!sfp) {
+ perror("Can't open file for reading");
+ return EXIT_FAILURE;
+ }
+
+ ret_val = fseek(sfp, 0L, SEEK_SET);
+ printf("DEBUG, after fseek, ret = %d\n", (int)ret_val);
+
+ uint64_t file_offset = 0;
+ file_offset = ftell(sfp);
+ printf("DEBUG: File offset = %lu\n", file_offset);
+
+ while ((wc = fgetwc(sfp)) != WEOF) {
+ putwchar(wc);
+ }
+
+ overall_ret += check_errno_and_print_dbg("fgetwc", file_type, wc);
+
+ ret_val = fseek(sfp, 0L, SEEK_SET);
+ printf("DEBUG, after fseek, ret = %d\n", (int)ret_val);
+
+ while ((wc = getwc(sfp)) != WEOF) {
+ putwchar(wc);
+ }
+
+ overall_ret += check_errno_and_print_dbg("getwc", file_type, wc);
+
+ ret_val = fseek(sfp, 0L, SEEK_SET);
+ printf("DEBUG, after fseek, ret = %d\n", (int)ret_val);
+
+ wc = getwc(sfp);
+ wc2 = ungetwc(wc, sfp);
+
+ overall_ret += check_errno_and_print_dbg("ungetwc", file_type, wc);
+
+ ret_val = fseek(sfp, 0L, SEEK_SET);
+ wc = fputwc(L'I', sfp);
+ overall_ret += check_errno_and_print_dbg("fputwc", file_type, wc);
+
+ wc = putwc(L'J', sfp);
+ overall_ret += check_errno_and_print_dbg("putwc", file_type, wc);
+
+ ret_val = fseek(sfp, 0L, SEEK_SET);
+
+ ret_str = fgetws(test_string, sizeof(test_string), sfp);
+
+ result = 0;
+ if (file_type == NORMAL) {
+ if (ret_str != NULL) {
+ if (wcsncmp(ret_str, test_string, wcslen(test_string)) == 0) {
+ result = 1;
+ }
+ }
+ } else if (file_type == PROTECTED && ret_str == NULL && errno == ENOTSUP) {
+ result = 1;
+ }
+
+ overall_ret += check_bool_and_print_dbg("fgetws", file_type, result, (char*)"");
+
+ ret_val = fputws(test_string, sfp);
+ result = 0;
+ if ((file_type == NORMAL && ret_val > 0) || (file_type == PROTECTED && ret_val == -1)) {
+ result = 1;
+ }
+ overall_ret += check_bool_and_print_dbg("fputws", file_type, result, (char*)"");
+
+ ret_val = fwide(sfp, 0);
+
+ result = 0;
+ if ((file_type == NORMAL && ret_val > 0) || (file_type == PROTECTED && ret_val == 0)) {
+ result = 1;
+ }
+ overall_ret += check_bool_and_print_dbg("fwide", file_type, result, (char*)"");
+
+ ret_val = wide_format_vfwscanf(sfp, L" %ls", test_string);
+ snprintf(sprintf_buf_glb, SPRINTF_BUFSIZE, "vfwscanf's ret = %d, errno=%d", ret_val, errno);
+
+ result = 0;
+ if ((file_type == NORMAL && errno == 0) || (file_type == PROTECTED && ret_val == -1)) {
+ result = 1;
+ }
+ overall_ret += check_bool_and_print_dbg("vfwscanf", file_type, result, (char*)sprintf_buf_glb);
+
+ ret_val = wide_format_vfwprintf(sfp, L"String with wide-char variable %ls.\n", L"arguments");
+ snprintf(sprintf_buf_glb, SPRINTF_BUFSIZE, "vfwprintf's ret = %d, errno=%d", ret_val, errno);
+
+ result = 0;
+ if ((file_type == NORMAL && errno == 0) || (file_type == PROTECTED && ret_val == -1)) {
+ result = 1;
+ }
+ overall_ret += check_bool_and_print_dbg("vfwprintf", file_type, result, (char*)sprintf_buf_glb);
+
+ fclose(sfp);
+
+ printf("\n#######%s, file_type=%s, %s#######\n", __func__, FILE_TYPE_STRING(file_type),
+ ZERO_RESULT(overall_ret));
+
+ return overall_ret;
+}
diff --git a/pfs/apps/pfs_app/run_app.sh b/pfs/apps/pfs_app/run_app.sh
new file mode 100755
index 0000000..769ee5a
--- /dev/null
+++ b/pfs/apps/pfs_app/run_app.sh
@@ -0,0 +1 @@
+SGX=1 ./pal_loader pfs_app
diff --git a/pfs/apps/pfs_app/sealed_custom_key b/pfs/apps/pfs_app/sealed_custom_key
new file mode 100644
index 0000000..d88a9a4
Binary files /dev/null and b/pfs/apps/pfs_app/sealed_custom_key differ
diff --git a/pfs/build_deps.sh b/pfs/build_deps.sh
new file mode 100755
index 0000000..863b986
--- /dev/null
+++ b/pfs/build_deps.sh
@@ -0,0 +1,106 @@
+#!/bin/bash
+
+#set -x
+
+DEFAULT_GRAPHENE_PATH=./deps/graphene
+install_graphene=0
+
+check_for_graphene_install()
+{
+ while true
+ do
+ echo "If you dont have graphene installed, this script will install graphene under default directory-path->"$DEFAULT_GRAPHENE_PATH
+ echo -n "Do you already have graphene installed in a non-default location? [yes/no] : "
+ read ANSWER
+
+ if [ "$ANSWER" == "yes" ]; then
+ install_graphene=0
+ break
+ elif [ "$ANSWER" == "no" ]; then
+ install_graphene=1
+ break
+ else
+ echo "you replied="$ANSWER", please type yes or no"
+ fi
+ done
+
+ echo "install_graphene var set to= "$install_graphene
+
+}
+
+if [[ ! -d $DEFAULT_GRAPHENE_PATH ]] ; then
+ check_for_graphene_install
+else
+ echo "graphene already setup in default path->"$DEFAULT_GRAPHENE_PATH
+fi
+
+# You need the SGX SDK and PSW installed.
+
+mkdir -p deps
+pushd deps
+
+if [ ! -d mbedtls ] ; then
+ git clone https://github.com/ARMmbed/mbedtls.git
+ pushd mbedtls
+ git checkout mbedtls-2.16.2
+ patch -p1 < ../../mbedtls_config_file_aesni.patch || exit 1
+ popd
+fi
+
+# Linux SGX SDK code
+# WARNING!! version of linux_sgx(i.e sgx_2.1.3) should
+# match with the one on top of which sgx-protectedfs is patched-for
+# in build_pfs_sdk.sh. Since both libraries(libfileops_interceptor.so
+# and libpfs_sdk.a should refer to the same version of sgx header files during
+# build and for compatibility.
+# Except for some header files under sdk/protected_fs which have been
+# modified with this patch.
+if [[ ! -d linux-sgx ]] ; then
+ git clone https://github.com/01org/linux-sgx.git
+ pushd linux-sgx
+ git checkout sgx_2.1.3
+ popd
+fi
+
+#After installing dependencies, we can
+#build sources in pfs_sdk directory, outside of deps directory.
+popd
+if [[ -d pfs_sdk ]] ; then
+ pushd pfs_sdk
+ ./build_pfs_sdk.sh || exit 1
+ popd
+fi
+pushd deps
+
+if [[ ! -d linux-sgx-driver ]] ; then
+ git clone https://github.com/01org/linux-sgx-driver.git
+ pushd linux-sgx-driver
+ git checkout sgx_driver_2.1
+ popd
+fi
+
+
+if [[ ! -d $DEFAULT_GRAPHENE_PATH && $install_graphene -eq 1 ]] ; then
+ git clone --recursive https://github.com/oscarlab/graphene.git
+ pushd graphene
+ #Note: below graphene commit works fine.
+ #git checkout aa9743dbcedeffe26ed71debeb07fe7ca4231bd7
+ openssl genrsa -3 -out Pal/src/host/Linux-SGX/signer/enclave-key.pem 3072
+ # The Graphene build process requires two inputs: (i) SGX driver directory, (ii) driver version.
+ # cannot use make -j`nproc` with Graphene's build process.
+ cd Pal/src/host/Linux-SGX/sgx-driver
+ printf "$(readlink -f ../../../../../../linux-sgx-driver)\n2.1\n" | ./link-intel-driver.py
+ cd -
+ printf "$(readlink -f ../linux-sgx-driver)\n2.1\n" | make SGX=1 || exit 1
+
+ # reduces the effort in the Graphene-SGX manifest file.
+ ln -s /usr/lib/x86_64-linux-gnu/libprotobuf-c.so.1 Runtime/
+ ln -s /usr/lib/libsgx_uae_service.so Runtime/
+ ln -s /lib/x86_64-linux-gnu/libcrypto.so.1.0.0 Runtime/
+ ln -s /lib/x86_64-linux-gnu/libz.so.1 Runtime/
+ ln -s /lib/x86_64-linux-gnu/libssl.so.1.0.0 Runtime/
+
+ popd
+fi
+
+popd # deps
diff --git a/pfs/build_library.sh b/pfs/build_library.sh
new file mode 100755
index 0000000..0abbe89
--- /dev/null
+++ b/pfs/build_library.sh
@@ -0,0 +1,5 @@
+make clean
+cd protected_fs_sdk
+./build_protected_fs_sdk.sh
+cd -
+make all
diff --git a/pfs/docs/design.md b/pfs/docs/design.md
new file mode 100755
index 0000000..db153d6
--- /dev/null
+++ b/pfs/docs/design.md
@@ -0,0 +1,616 @@
+Design of the Graphene Protected Filesystem Shield
+===============================================================================
+* **Author:** *Sudha Krishnakumar *, *Michael Steiner, *
+* **Version:** *0.4*
+
+# Context and Problem Statement #
+
+The *Graphene Filesystem Shield* is extends *[Graphene](https://grapheneproject.io/)*, a system
+which allows existing binaries to run inside SGX, with
+transparent protection of file I/O. More specifically, it
+transparently intercepts all _file I/O_ calls and, if the implied
+filename is below some pre-specified mount-points, cryptographically
+protects the corresponding operations while interacting with the
+untrusted filesystem. The (hierachy of) files below a
+specific mount-points is called a _volume_. Each volume is represented
+also as a sub-directory (hierachy) in the untrusted filesystem (in the
+current version there is a one-to-one correspondence of files to the
+trusted space in addition to a few meta-data files although that might
+change in the future and no assumptions should be made on structure
+and content).
+
+## Security Properties ##
+
+Let us first list security properties which we might desire from such
+a system. Later we will discuss their relative importance and which
+can be handled where and how.
+
+* File Content
+ * *File Content Confidentiality (**FCC**)*: All file content is
+ hidden from an attacker.
+ * *File Content Integrity (**FCI**)*: No attacker is able to tamper
+ with file content without detection.
+
+* File Metadata
+ * *Filename Integrity (**FNI**)*: No attacker is able to tamper
+ with basename of a file without detection, e.g., she cannot rename
+ protected files.
+ * *Filename Confidentiality (**FNC**)*: The basename of files is
+ hidden from attackers.
+ * *File Attribute Integrity (**FAI**)*: File attributes like
+ permissions, file-type (e.g., symbolic links), owners or
+ modification times cannot be tampered with.
+ * *File Attribute Confidentiality (**FAC**)*: File attributes like
+ permissions, owners or modification times are hidden from attacker.
+ * *File Existence Integrity (**FEI**)*: An attacker cannot hide a
+ previously created protected file.
+
+* Volume Metadata
+ * *Path Integrity (**PI**)*: An adversary cannot tamper with the
+ complete pathname inside a volume, i.e., he cannot move a protected
+ file to a different sub-directory under the same mount-point.
+ * *Directory Name Confidentiality (**DNC**)*: An attacker doesn't
+ learn the names of directories.
+ * *Volume Binding (**VB**)*: Protected files are tied to a
+ specific volume, i.e., an attacker cannot move or duplicate files
+ from one volume to another one volume, whether they are mounted
+ for the same graphene application instance at two different
+ mount-points or two different graphene application instances at
+ the same mount-point path.
+
+* Other
+ * *Rollback Protection (**RP**)*: An adversary is unable to revert the
+ state to earlier version. State can refer to (parts of a) files as
+ well as meta-data (e.g., existence of file).
+ * *Access Patterns Hiding (**APH**)*: Prevent the adversary from inferring
+ information on file content based on access patterns. Some aspects
+ of are *File Existence Hiding*, *Path Hiding* or alike.
+
+
+## ProtectFS ##
+The SGX SDK already provides file-based encryption and integrity
+protection in form of the ProtectFS functions (see [SGX Developer Guide](https://software.intel.com/sites/default/files/managed/47/19/sgx-sdk-developer-reference-for-windows-os.pdf). More specifically, it provides FCC, FCI and
+FNI. As it assumes a flat non-hierachical namespace, PI, DNC, VB are
+out-of-scope.
+
+It is targeted for greenfield applications, which usually can ensure
+that filenames do not leak sensitive information. Hence the absence of
+FNC is not an issue. Similarly, such applications can easily adapt to
+the absence of FAI, FAC and FEI.
+
+RP is currently not supported. However, the architecture and code is
+prepared for rapid enablement once a scalable monotonic counter
+solution exists.
+
+APH is also considered out-of-scope: Susceptability of attacks
+exploiting access patterns is highly application dependent and
+requires more sophisticated exploitation techniques. If protection is
+required, the application might have to adopt "usual" side-channel
+protection techniques for file access and/or a protected file-system
+based (expensive) ORAM techiques might have to be implemented.
+
+
+## Implications for Graphene Filesystem Shield ##
+
+Basing the filesystem shield on ProtectFS seems a natural approach. As
+mentioned above, it already provides key security properties. However,
+in the Graphene case, we have no control over assumptions made by
+application, e.g., filenames could contain sensitive information,
+graphene exposes a hierchical filenname space and the application
+might require multiple volumes mounted to multiple mount points. Hence
+FNC, DNC, PI and VB cannot be as easily dismissed.
+
+In the following, we discuss some lightweight extensions to ProtectFS
+which can provide some of these properties.
+
+RP, as mentioned in the section on ProtectFS, will have to wait until
+there is a scalable monotonic counter solution integrated into
+ProtectFS, but then will naturally translate also to the shield.
+
+To provide strong RP covering also meta-data. To achieve this, one
+would require a quite different approached based on block-level
+security, like dm-crypt, dm-verity and/or
+[dm-x](https://github.com/anrinch/dmx) with an in-graphene filesystem
+(similar to [lkl-sgx](https://github.com/lsds/sgx-lkl)). This would
+also provide some form of) ABH. However, it would require a
+considerable larger effort to build and is currently out-of-scope.
+
+
+# Design Overview #
+
+File I/O is intercepted (based on an `LD_PRELOAD` handler) and files
+behind a mount-point are protected using ProtectFS. However,
+additionally, we preprocess filenames such that the names visible to
+the untrusted system is encrypted and additionally tied to volume and
+path-name.
+
+More specifically
+
+- each volume has associate *volume meta data* containing volumne ID,
+ key-type and information required for key-derivation such as
+ MRSIGNER, CPUSVN, ISVSVN and KEY-ID. The volume meta data is created
+ and managed by shield and stored in (hidden/special) file in root
+ directory of a volume. The metadata should be bound to the graphene
+ manifest for pre-existing volumes so a party interacting with the
+ graphene application can track use of volumes across application
+ instances based on attestation.
+
+- For each intercepted graphene application functions involving
+ filenames in protected volumes, we encrypts file-name's path
+ components before passing the call with encrypted filename to
+ ProtectFS or other related functions (e.g., opendir). The
+ encryption performed based on a deterministic tweakable wide-block
+ cipher with the filename padded to equal length and with (hash of)
+ volumne-id and path-prefix as tweak.
+
+- Similarly, intercepted functions where a filename is passed
+ from the untrusted system, e.g., readdir, will be decrypted and
+ passed in clear to the graphene application.
+
+The encryption will ensure FNC and, potentially, DNC. Redundancy in
+the filename encoding ensures that anything violating PI and VB is
+detected during decryption.
+
+The design supports both key-management types of ProtectFS, `seal` and
+`custom`. See below for more details on the key-management. In
+particular, note though that custom keys passed to the shield are
+_not_ passed to protectfs but used to derive a separate custom key
+which is passed to ProtectFS.
+
+
+# Design Details #
+
+## Volume Metadata ##
+
+### Data structures ###
+
+ struct {
+ protected-data: struct {
+ key-type: { "custom", "seal" }
+ key-derivation data: struct {
+ key-id: sgx_key_id_t
+ union {
+ case key-type=="custom":
+ case key-type=="seal": struct {
+ cpusvn: SVN
+ isvsvn: SVN,
+ MRSIGNER
+ }
+ }
+ }
+ }
+ vol-id = MAC_VMK(protected-data)
+ }
+
+`MAC` is `CMAC-AES128` [[NIST SP800-38B]](https://csrc.nist.gov/publications/detail/sp/800-38b/archive/2005-05-01).
+The key `VMK` is defined below in section keys.
+
+- **MAC Encoding in Voume-meta-data:** Encoding of payload for MAC (i.e., vol-id of
+ protected-data blob) is the byte-sequence of a c-struct
+ corresponding to `protected-data` from above.
+
+### Volume Metadata File name ###
+- A (hidden) file named as `.protectfs_vol_md.json` under (volume root
+directory, referred as `PFS_MOUNT_POINT` in graphene manifest).
+**TODO (For implementation)**: Current implementation outputs a binary file
+`.protectfs_vol_md.bin`, will be changed, once json format is supported.
+
+### Volume Metadata File encoding ###
+- Will be encoded in json, so that it is human readable, and allows
+ for easy extraction of the volume-id (which is required
+ to set `vol-id` field in manifest!)
+**TODO (For implementation)**: Currently implementation stores this file
+in binary format. To be changed to json in future.
+
+
+### Volume binding in Graphene Manifest ###
+The Graphene manifest will be extended with following
+(per-volume/mountpoint) values:
+- *`PFS_MOUNT_POINT` (referred as `mount-point` in this doc)* :
+ the mount point in the graphene internal namespace
+ below the volume is mounted (already existing in current implementation)
+- *`PFS_VOL_ID` (referred as `vol-id` in this doc)*: the id of a pre-existing
+volume to mount (optional,
+ mutually exclusive with `allow-reuse`)
+- *`PFS_ALLOW_REUSE` (referred as `allow-reuse` in this doc)* : defines whether
+ in absence of `vol-id` an existing volume under the mount point can be re-used
+ or a new volume must be created (optional, mutually exclusive with `vol-id`,
+ default false)
+
+Below we will refer to them as mf.mount-point, mf.vol-id and
+mf.allow-reuse for some particular manifest mf
+
+**TODO (For implementation)**:
+ In the future, if implementation supports multiple volumes, naming scheme is
+ likely to change. For example, each volume's attributes can be grouped
+ under a label, and set in the manifest (somewhat matching the mount point
+ mappings in the standard graphene manifest, like `PFS.mount.