static int my_fuse_opt_proc()

in src/s3fs.cpp [3947:4772]


static int my_fuse_opt_proc(void* data, const char* arg, int key, struct fuse_args* outargs)
{
    int ret;
    if(key == FUSE_OPT_KEY_NONOPT){
        // the first NONOPT option is the bucket name
        if(S3fsCred::GetBucket().empty()){
            if ((ret = set_bucket(arg))){
                return ret;
            }
            return 0;
        }else if (!strcmp(arg, "ossfs")) {
            return 0;
        }

        // the second NONOPT option is the mountpoint(not utility mode)
        if(mountpoint.empty() && NO_UTILITY_MODE == utility_mode){
            // save the mountpoint and do some basic error checking
            mountpoint = arg;
            struct stat stbuf;

// In MSYS2 environment with WinFsp, it is not needed to create the mount point before mounting.
// Also it causes a conflict with WinFsp's validation, so disabling it.
#ifdef __MSYS__
            memset(&stbuf, 0, sizeof stbuf);
            set_mountpoint_attribute(stbuf);
#else
            if(stat(arg, &stbuf) == -1){
                S3FS_PRN_EXIT("unable to access MOUNTPOINT %s: %s", mountpoint.c_str(), strerror(errno));
                return -1;
            }
            if(!(S_ISDIR(stbuf.st_mode))){
                S3FS_PRN_EXIT("MOUNTPOINT: %s is not a directory.", mountpoint.c_str());
                return -1;
            }
            if(!set_mountpoint_attribute(stbuf)){
                S3FS_PRN_EXIT("MOUNTPOINT: %s permission denied.", mountpoint.c_str());
                return -1;
            }

            if(!nonempty){
                struct dirent *ent;
                DIR *dp = opendir(mountpoint.c_str());
                if(dp == NULL){
                    S3FS_PRN_EXIT("failed to open MOUNTPOINT: %s: %s", mountpoint.c_str(), strerror(errno));
                    return -1;
                }
                while((ent = readdir(dp)) != NULL){
                    if(strcmp(ent->d_name, ".") != 0 && strcmp(ent->d_name, "..") != 0){
                        closedir(dp);
                        S3FS_PRN_EXIT("MOUNTPOINT directory %s is not empty. if you are sure this is safe, can use the 'nonempty' mount option.", mountpoint.c_str());
                        return -1;
                    }
                }
                closedir(dp);
            }
#endif
            return 1;
        }

        // Unknown option
        if(NO_UTILITY_MODE == utility_mode){
            S3FS_PRN_EXIT("specified unknown third option(%s).", arg);
        }else{
            S3FS_PRN_EXIT("specified unknown second option(%s). you don't need to specify second option(mountpoint) for utility mode(-u).", arg);
        }
        return -1;

    }else if(key == FUSE_OPT_KEY_OPT){
        if(is_prefix(arg, "uid=")){
            s3fs_uid = get_uid(strchr(arg, '=') + sizeof(char));
            if(0 != geteuid() && 0 == s3fs_uid){
                S3FS_PRN_EXIT("root user can only specify uid=0.");
                return -1;
            }
            is_s3fs_uid = true;
            return 1; // continue for fuse option
        }
        if(is_prefix(arg, "gid=")){
            s3fs_gid = get_gid(strchr(arg, '=') + sizeof(char));
            if(0 != getegid() && 0 == s3fs_gid){
                S3FS_PRN_EXIT("root user can only specify gid=0.");
                return -1;
            }
            is_s3fs_gid = true;
            return 1; // continue for fuse option
        }
        if(is_prefix(arg, "umask=")){
            off_t s3fs_umask_tmp = cvt_strtoofft(strchr(arg, '=') + sizeof(char), /*base=*/ 8);
            s3fs_umask = s3fs_umask_tmp & (S_IRWXU | S_IRWXG | S_IRWXO);
            is_s3fs_umask = true;
            return 1; // continue for fuse option
        }
        if(0 == strcmp(arg, "allow_other")){
            allow_other = true;
            return 1; // continue for fuse option
        }
        if(is_prefix(arg, "mp_umask=")){
            off_t mp_umask_tmp = cvt_strtoofft(strchr(arg, '=') + sizeof(char), /*base=*/ 8);
            mp_umask = mp_umask_tmp & (S_IRWXU | S_IRWXG | S_IRWXO);
            is_mp_umask = true;
            return 0;
        }
        if(is_prefix(arg, "default_acl=")){
            const char* acl_string = strchr(arg, '=') + sizeof(char);
            acl_t acl = acl_t::from_str(acl_string);
            if(acl == acl_t::UNKNOWN){
                S3FS_PRN_EXIT("unknown value for default_acl: %s", acl_string);
                return -1;
            }
            S3fsCurl::SetDefaultAcl(acl);
            return 0;
        }
        if(is_prefix(arg, "retries=")){
            off_t retries = cvt_strtoofft(strchr(arg, '=') + sizeof(char), /*base=*/ 10);
            if(retries == 0){
                S3FS_PRN_EXIT("retries must be greater than zero");
                return -1;
            }
            S3fsCurl::SetRetries(static_cast<int>(retries));
            return 0;
        }
        if(is_prefix(arg, "tmpdir=")){
            FdManager::SetTmpDir(strchr(arg, '=') + sizeof(char));
            return 0;
        }
        if(is_prefix(arg, "use_cache=")){
            FdManager::SetCacheDir(strchr(arg, '=') + sizeof(char));
            return 0;
        }
        if(0 == strcmp(arg, "check_cache_dir_exist")){
            FdManager::SetCheckCacheDirExist(true);
            return 0;
        }
        if(0 == strcmp(arg, "del_cache")){
            is_remove_cache = true;
            return 0;
        }
        if(is_prefix(arg, "multireq_max=")){
            int maxreq = static_cast<int>(cvt_strtoofft(strchr(arg, '=') + sizeof(char), /*base=*/ 10));
            S3fsCurl::SetMaxMultiRequest(maxreq);
            return 0;
        }
        if(0 == strcmp(arg, "nonempty")){
            nonempty = true;
            return 1; // need to continue for fuse.
        }
        if(0 == strcmp(arg, "nomultipart")){
            nomultipart = true;
            return 0;
        }
        /*
        // old format for storage_class
        if(0 == strcmp(arg, "use_rrs") || is_prefix(arg, "use_rrs=")){
            off_t rrs = 1;
            // for an old format.
            if(is_prefix(arg, "use_rrs=")){
                rrs = cvt_strtoofft(strchr(arg, '=') + sizeof(char), 10); //base=
            }
            if(0 == rrs){
                S3fsCurl::SetStorageClass("STANDARD");
            }else if(1 == rrs){
                S3fsCurl::SetStorageClass("REDUCED_REDUNDANCY");
            }else{
                S3FS_PRN_EXIT("poorly formed argument to option: use_rrs");
                return -1;
            }
            return 0;
        }
        */
        if(is_prefix(arg, "storage_class=")){
            const char *storage_class = strchr(arg, '=') + sizeof(char);
            S3fsCurl::SetStorageClass(storage_class);
            return 0;
        }
        //
        // [NOTE]
        // use_sse                        Set Server Side Encrypting type to SSE-OSS
        // use_sse=1
        // use_sse=file                   Set Server Side Encrypting type to Custom key(SSE-C) and load custom keys
        // use_sse=custom(c):file
        // use_sse=custom(c)              Set Server Side Encrypting type to Custom key(SSE-C)
        // use_sse=kmsid(k):kms-key-id    Set Server Side Encrypting type to Alibaba Cloud Key Management key id(SSE-KMS) and load KMS id
        // use_sse=kmsid(k)               Set Server Side Encrypting type to Alibaba Cloud Key Management key id(SSE-KMS)
        // use_sse=kms                    Set Server Side Encrypting type to default customer master key(CMK) managed by KMS (SSE-KMS
        //
        // load_sse_c=file                Load Server Side Encrypting custom keys
        //
        // OSSSSECKEYS                    Loading Environment for Server Side Encrypting custom keys
        // OSSSSECKEYS                    Loading Environment for Server Side Encrypting Key id
        //
        if(is_prefix(arg, "use_sse")){
            if(0 == strcmp(arg, "use_sse") || 0 == strcmp(arg, "use_sse=1")){ // use_sse=1 is old type parameter
                // sse type is SSE_OSS
                if(!S3fsCurl::IsSseDisable() && !S3fsCurl::IsSseS3Type()){
                    S3FS_PRN_EXIT("already set SSE another type, so conflict use_sse option or environment.");
                    return -1;
                }
                S3fsCurl::SetSseType(sse_type_t::SSE_OSS);

            }else if(0 == strcmp(arg, "use_sse=kmsid") || 0 == strcmp(arg, "use_sse=k")){
                // sse type is SSE_KMS with out kmsid(expecting id is loaded by environment)
                if(!S3fsCurl::IsSseDisable() && !S3fsCurl::IsSseKmsType()){
                    S3FS_PRN_EXIT("already set SSE another type, so conflict use_sse option or environment.");
                    return -1;
                }
                if(!S3fsCurl::IsSetSseKmsId()){
                    S3FS_PRN_EXIT("use_sse=kms but not loaded kms id by environment.");
                    return -1;
                }
                S3fsCurl::SetSseType(sse_type_t::SSE_KMS);

            }else if(is_prefix(arg, "use_sse=kmsid:") || is_prefix(arg, "use_sse=k:")){
                // sse type is SSE_KMS with kmsid
                if(!S3fsCurl::IsSseDisable() && !S3fsCurl::IsSseKmsType()){
                    S3FS_PRN_EXIT("already set SSE another type, so conflict use_sse option or environment.");
                    return -1;
                }
                const char* kmsid;
                if(is_prefix(arg, "use_sse=kmsid:")){
                    kmsid = &arg[strlen("use_sse=kmsid:")];
                }else{
                    kmsid = &arg[strlen("use_sse=k:")];
                }
                if(!S3fsCurl::SetSseKmsid(kmsid)){
                    S3FS_PRN_EXIT("failed to load use_sse kms id.");
                    return -1;
                }
                S3fsCurl::SetSseType(sse_type_t::SSE_KMS);

            }else if(0 == strcmp(arg, "use_sse=kms")){
                // sse type is SSE_KMS without kmsid, uses the default customer master key(CMK) managed by KMS.
                if(!S3fsCurl::IsSseDisable() && !S3fsCurl::IsSseKmsType()){
                    S3FS_PRN_EXIT("already set SSE another type, so conflict use_sse option or environment.");
                    return -1;
                }
                S3fsCurl::SetSseType(sse_type_t::SSE_KMS);
                S3fsCurl::SetSseCMK(true);
            }
            /*
            else if(0 == strcmp(arg, "use_sse=custom") || 0 == strcmp(arg, "use_sse=c")){
                // sse type is SSE_C with out custom keys(expecting keys are loaded by environment or load_sse_c option)
                if(!S3fsCurl::IsSseDisable() && !S3fsCurl::IsSseCType()){
                    S3FS_PRN_EXIT("already set SSE another type, so conflict use_sse option or environment.");
                    return -1;
                }
                // [NOTE]
                // do not check ckeys exists here.
                //
                S3fsCurl::SetSseType(sse_type_t::SSE_C);

            }else if(is_prefix(arg, "use_sse=custom:") || is_prefix(arg, "use_sse=c:")){
                // sse type is SSE_C with custom keys
                if(!S3fsCurl::IsSseDisable() && !S3fsCurl::IsSseCType()){
                    S3FS_PRN_EXIT("already set SSE another type, so conflict use_sse option or environment.");
                    return -1;
                }
                const char* ssecfile;
                if(is_prefix(arg, "use_sse=custom:")){
                    ssecfile = &arg[strlen("use_sse=custom:")];
                }else{
                    ssecfile = &arg[strlen("use_sse=c:")];
                }
                if(!S3fsCurl::SetSseCKeys(ssecfile)){
                    S3FS_PRN_EXIT("failed to load use_sse custom key file(%s).", ssecfile);
                    return -1;
                }
                S3fsCurl::SetSseType(sse_type_t::SSE_C);

            }else if(0 == strcmp(arg, "use_sse=")){    // this type is old style(parameter is custom key file path)
                // SSE_C with custom keys.
                const char* ssecfile = &arg[strlen("use_sse=")];
                if(!S3fsCurl::SetSseCKeys(ssecfile)){
                    S3FS_PRN_EXIT("failed to load use_sse custom key file(%s).", ssecfile);
                    return -1;
                }
                S3fsCurl::SetSseType(sse_type_t::SSE_C);

            }*/
            else{
                // never come here.
                S3FS_PRN_EXIT("something wrong use_sse option.");
                return -1;
            }
            return 0;
        }
        // [NOTE]
        // Do only load SSE custom keys, care for set without set sse type.
        /*
        if(is_prefix(arg, "load_sse_c=")){
            const char* ssecfile = &arg[strlen("load_sse_c=")];
            if(!S3fsCurl::SetSseCKeys(ssecfile)){
                S3FS_PRN_EXIT("failed to load use_sse custom key file(%s).", ssecfile);
                return -1;
            }
            return 0;
        }
        */
        if(is_prefix(arg, "ssl_verify_hostname=")){
            long sslvh = static_cast<long>(cvt_strtoofft(strchr(arg, '=') + sizeof(char), /*base=*/ 10));
            if(-1 == S3fsCurl::SetSslVerifyHostname(sslvh)){
                S3FS_PRN_EXIT("poorly formed argument to option: ssl_verify_hostname.");
                return -1;
            }
            return 0;
        }
        //
        // Detect options for credential
        //
        if(0 >= (ret = ps3fscred->DetectParam(arg))){
            if(0 > ret){
                return -1;
            }
            return 0;
        }
        if(is_prefix(arg, "public_bucket=")){
            off_t pubbucket = cvt_strtoofft(strchr(arg, '=') + sizeof(char), /*base=*/ 10);
            if(1 == pubbucket){
                S3fsCurl::SetPublicBucket(true);
                // [NOTE]
                // if bucket is public(without credential), s3 do not allow copy api.
                // so ossfs sets nocopyapi mode.
                //
                nocopyapi = true;
            }else if(0 == pubbucket){
                S3fsCurl::SetPublicBucket(false);
            }else{
                S3FS_PRN_EXIT("poorly formed argument to option: public_bucket.");
                return -1;
            }
            return 0;
        }
        if(is_prefix(arg, "bucket=")){
            std::string bname = strchr(arg, '=') + sizeof(char);
            if ((ret = set_bucket(bname.c_str()))){
                return ret;
            }
            return 0;
        }
        if(0 == strcmp(arg, "no_check_certificate")){
            S3fsCurl::SetCheckCertificate(false);
            return 0;
        }
        if(is_prefix(arg, "connect_timeout=")){
            long contimeout = static_cast<long>(cvt_strtoofft(strchr(arg, '=') + sizeof(char), /*base=*/ 10));
            S3fsCurl::SetConnectTimeout(contimeout);
            return 0;
        }
        if(is_prefix(arg, "readwrite_timeout=")){
            time_t rwtimeout = static_cast<time_t>(cvt_strtoofft(strchr(arg, '=') + sizeof(char), /*base=*/ 10));
            S3fsCurl::SetReadwriteTimeout(rwtimeout);
            return 0;
        }
        if(is_prefix(arg, "list_object_max_keys=")){
            int max_keys = static_cast<int>(cvt_strtoofft(strchr(arg, '=') + sizeof(char), /*base=*/ 10));
            if(max_keys < 1000){
                S3FS_PRN_EXIT("argument should be over 1000: list_object_max_keys");
                return -1;
            }
            max_keys_list_object = max_keys;
            return 0;
        }
        if(is_prefix(arg, "max_stat_cache_size=")){
            unsigned long cache_size = static_cast<unsigned long>(cvt_strtoofft(strchr(arg, '=') + sizeof(char), 10));
            StatCache::getStatCacheData()->SetCacheSize(cache_size);
            return 0;
        }
        if(is_prefix(arg, "stat_cache_expire=")){
            auto value = cvt_strtoofft(strchr(arg, '=') + sizeof(char), /*base=*/ 10);
            if(value == -1){
                S3FS_PRN_WARN("stat_cache_expire is set to -1, unset expiretime.");
                StatCache::getStatCacheData()->UnsetExpireTime();
                return 0;
            }
            time_t expr_time = static_cast<time_t>(value);
            StatCache::getStatCacheData()->SetExpireTime(expr_time);
            return 0;
        }
        // [NOTE]
        // This option is for compatibility old version.
        if(is_prefix(arg, "stat_cache_interval_expire=")){
            time_t expr_time = static_cast<time_t>(cvt_strtoofft(strchr(arg, '=') + sizeof(char), /*base=*/ 10));
            StatCache::getStatCacheData()->SetExpireTime(expr_time, true);
            return 0;
        }
        if(0 == strcmp(arg, "disable_noobj_cache")){
            StatCache::getStatCacheData()->DisableCacheNoObject();
            return 0;
        }
        if(0 == strcmp(arg, "nodnscache")){
            S3fsCurl::SetDnsCache(false);
            return 0;
        }
        if(0 == strcmp(arg, "nosscache")){
            S3fsCurl::SetSslSessionCache(false);
            return 0;
        }
        if(is_prefix(arg, "parallel_count=") || is_prefix(arg, "parallel_upload=")){
            int maxpara = static_cast<int>(cvt_strtoofft(strchr(arg, '=') + sizeof(char), /*base=*/ 10));
            if(0 >= maxpara){
                S3FS_PRN_EXIT("argument should be over 1: parallel_count");
                return -1;
            }
            S3fsCurl::SetMaxParallelCount(maxpara);
            return 0;
        }
        if(is_prefix(arg, "fd_page_size=")){
            S3FS_PRN_ERR("option fd_page_size is no longer supported, so skip this option.");
            return 0;
        }
        if(is_prefix(arg, "multipart_size=")){
            off_t size = static_cast<off_t>(cvt_strtoofft(strchr(arg, '=') + sizeof(char), /*base=*/ 10));
            if(!S3fsCurl::SetMultipartSize(size)){
                S3FS_PRN_EXIT("multipart_size option must be at least 5 MB.");
                return -1;
            }
            return 0;
        }
        if(is_prefix(arg, "multipart_copy_size=")){
            off_t size = static_cast<off_t>(cvt_strtoofft(strchr(arg, '=') + sizeof(char), /*base=*/ 10));
            if(!S3fsCurl::SetMultipartCopySize(size)){
                S3FS_PRN_EXIT("multipart_copy_size option must be at least 5 MB.");
                return -1;
            }
            return 0;
        }
        if(is_prefix(arg, "max_dirty_data=")){
            off_t size = static_cast<off_t>(cvt_strtoofft(strchr(arg, '=') + sizeof(char), /*base=*/ 10));
            if(size >= 50){
                size *= 1024 * 1024;
            }else if(size != -1){
                S3FS_PRN_EXIT("max_dirty_data option must be at least 50 MB.");
                return -1;
            }
            max_dirty_data = size;
            return 0;
        }
        if(is_prefix(arg, "free_space_ratio=")){
            int ratio = static_cast<int>(cvt_strtoofft(strchr(arg, '=') + sizeof(char), /*base=*/ 10));
            if(FdManager::GetEnsureFreeDiskSpace()!=0){
                S3FS_PRN_EXIT("option free_space_ratio conflicts with ensure_diskfree, please set only one of them.");
                return -1;
            }
            if(ratio < 0 || ratio > 100){
                S3FS_PRN_EXIT("option free_space_ratio must between 0 to 100, which is: %d", ratio);
                return -1;
            }
            off_t dfsize = FdManager::GetTotalDiskSpaceByRatio(ratio);
            S3FS_PRN_INFO("Free space ratio set to %d %%, ensure the available disk space is greater than %.3f MB", ratio, static_cast<double>(dfsize) / 1024 / 1024);
            if(dfsize < S3fsCurl::GetMultipartSize()){
                S3FS_PRN_WARN("specified size to ensure disk free space is smaller than multipart size, so set multipart size to it.");
                dfsize = S3fsCurl::GetMultipartSize();
            }
            FdManager::SetEnsureFreeDiskSpace(dfsize);
            return 0;
        }
        if(is_prefix(arg, "ensure_diskfree=")){
            off_t dfsize = cvt_strtoofft(strchr(arg, '=') + sizeof(char), /*base=*/ 10) * 1024 * 1024;
            
            if(FdManager::GetEnsureFreeDiskSpace()!=0){
                S3FS_PRN_EXIT("option free_space_ratio conflicts with ensure_diskfree, please set only one of them.");
                return -1;
            }
            S3FS_PRN_INFO("Set and ensure the available disk space is greater than %.3f MB.", static_cast<double>(dfsize) / 1024 / 1024);

            if(dfsize < S3fsCurl::GetMultipartSize()){
                S3FS_PRN_WARN("specified size to ensure disk free space is smaller than multipart size, so set multipart size to it.");
                dfsize = S3fsCurl::GetMultipartSize();
            }
            FdManager::SetEnsureFreeDiskSpace(dfsize);
            return 0;
        }
        if(is_prefix(arg, "fake_diskfree=")){
            S3FS_PRN_WARN("The fake_diskfree option was specified. Use this option for testing or debugging.");

            // [NOTE] This value is used for initializing to FdManager after parsing all options.
            fake_diskfree_size = cvt_strtoofft(strchr(arg, '=') + sizeof(char), /*base=*/ 10) * 1024 * 1024;
            return 0;
        }
        if(is_prefix(arg, "multipart_threshold=")){
            multipart_threshold = static_cast<int64_t>(cvt_strtoofft(strchr(arg, '=') + sizeof(char), /*base=*/ 10)) * 1024 * 1024;
            if(multipart_threshold <= MIN_MULTIPART_SIZE){
                S3FS_PRN_EXIT("multipart_threshold must be at least %lld, was: %lld", static_cast<long long>(MIN_MULTIPART_SIZE), static_cast<long long>(multipart_threshold));
                return -1;
            }
            return 0;
        }
        if(is_prefix(arg, "singlepart_copy_limit=")){
            singlepart_copy_limit = static_cast<int64_t>(cvt_strtoofft(strchr(arg, '=') + sizeof(char), /*base=*/ 10)) * 1024 * 1024;
            return 0;
        }
        if(is_prefix(arg, "ahbe_conf=")){
            std::string ahbe_conf = strchr(arg, '=') + sizeof(char);
            if(!AdditionalHeader::get()->Load(ahbe_conf.c_str())){
                S3FS_PRN_EXIT("failed to load ahbe_conf file(%s).", ahbe_conf.c_str());
                return -1;
            }
            AdditionalHeader::get()->Dump();
            return 0;
        }
        if(0 == strcmp(arg, "noxmlns")){
            noxmlns = true;
            return 0;
        }
        if(0 == strcmp(arg, "nomixupload")){
            FdEntity::SetNoMixMultipart();
            return 0;
        }
        if(0 == strcmp(arg, "nocopyapi")){
            nocopyapi = true;
            return 0;
        }
        if(0 == strcmp(arg, "norenameapi")){
            norenameapi = true;
            return 0;
        }
        if(0 == strcmp(arg, "complement_stat")){
            complement_stat = true;
            return 0;
        }
        if(0 == strcmp(arg, "notsup_compat_dir")){
            support_compat_dir = false;
            return 0;
        }
        if(0 == strcmp(arg, "enable_content_md5")){
            S3fsCurl::SetContentMd5(true);
            return 0;
        }
        if(0 == strcmp(arg, "enable_unsigned_payload")){
            S3fsCurl::SetUnsignedPayload(true);
            return 0;
        }
        if(is_prefix(arg, "host=")){
            s3host = strchr(arg, '=') + sizeof(char);
            return 0;
        }
        if(is_prefix(arg, "servicepath=")){
            service_path = strchr(arg, '=') + sizeof(char);
            return 0;
        }
        if(is_prefix(arg, "url=")){
            s3host = strchr(arg, '=') + sizeof(char);
            // strip the trailing '/', if any, off the end of the host
            // std::string
            size_t found, length;
            found  = s3host.find_last_of('/');
            length = s3host.length();
            while(found == (length - 1) && length > 0){
                s3host.erase(found);
                found  = s3host.find_last_of('/');
                length = s3host.length();
            }
            /*
            // Check url for http / https protocol std::string
            if(!is_prefix(s3host.c_str(), "https://") && !is_prefix(s3host.c_str(), "http://")){
                S3FS_PRN_EXIT("option url has invalid format, missing http / https protocol");
                return -1;
            }
            */
            return 0;
        }
        if(0 == strcmp(arg, "sigv1")){
            S3fsCurl::SetSignatureType(V1_ONLY);
            return 0;
        }
        if(is_prefix(arg, "endpoint=")){
            endpoint              = strchr(arg, '=') + sizeof(char);
            is_specified_endpoint = true;
            return 0;
        }
        if(0 == strcmp(arg, "use_path_request_style")){
            pathrequeststyle = true;
            return 0;
        }
        if(0 == strcmp(arg, "noua")){
            S3fsCurl::SetUserAgentFlag(false);
            return 0;
        }
        if(0 == strcmp(arg, "listobjectsv2")){
            S3fsCurl::SetListObjectsV2(true);
            return 0;
        }
        if(0 == strcmp(arg, "use_xattr")){
            is_use_xattr = true;
            return 0;
        }else if(is_prefix(arg, "use_xattr=")){
            const char* strflag = strchr(arg, '=') + sizeof(char);
            if(0 == strcmp(strflag, "1")){
                is_use_xattr = true;
            }else if(0 == strcmp(strflag, "0")){
                is_use_xattr = false;
            }else{
                S3FS_PRN_EXIT("option use_xattr has unknown parameter(%s).", strflag);
                return -1;
            }
            return 0;
        }
        if(is_prefix(arg, "cipher_suites=")){
            cipher_suites = strchr(arg, '=') + sizeof(char);
            return 0;
        }
        if(is_prefix(arg, "instance_name=")){
            instance_name = strchr(arg, '=') + sizeof(char);
            instance_name = "[" + instance_name + "]";
            return 0;
        }
        if(is_prefix(arg, "mime=")){
            mimetype_file = strchr(arg, '=') + sizeof(char);
            return 0;
        }
        if(is_prefix(arg, "upload_traffic_limit=")){
            long traffic_limit = static_cast<long>(cvt_strtoofft(strchr(arg, '=') + sizeof(char), /*base=*/ 10));
            S3fsCurl::SetUploadTrafficLimit(traffic_limit);
            return 0;
        }
        if(is_prefix(arg, "download_traffic_limit=")){
            long traffic_limit = static_cast<long>(cvt_strtoofft(strchr(arg, '=') + sizeof(char), /*base=*/ 10));
            S3fsCurl::SetDownloadTrafficLimit(traffic_limit);
            return 0;
        }
        if(0 == strcmp(arg, "noshallowcopyapi")){
            shallowcopyapi = false;
            return 0;
        }
        if(0 == strcmp(arg, "readdir_optimize")){
            is_readdir_optimize = true;
            return 0;
        }
        if(is_prefix(arg, "readdir_check_size=")){
            readdir_check_size = static_cast<off_t>(cvt_strtoofft(strchr(arg, '=') + sizeof(char), /*base=*/ 10));
            return 0;
        }
        if(0 == strcmp(arg, "symlink_in_meta")){
            is_new_symlink_format = true;
            return 0;
        }       
        if(0 == strcmp(arg, "direct_read")){
            direct_read = true;
            return 0;
        }
        if(is_prefix(arg, "direct_read_prefetch_thread=")){
            int max_thcount = static_cast<int>(cvt_strtoofft(strchr(arg, '=') + sizeof(char), /*base=*/ 10));
            if(0 >= max_thcount){
                S3FS_PRN_EXIT("direct_read_max_prefetch_thread_count should be over 1");
                return -1;
            }
            direct_read_max_prefetch_thread_count = max_thcount;
            return 0;
        }
        if(is_prefix(arg, "direct_read_chunk_size=")){
            off_t size = static_cast<off_t>(cvt_strtoofft(strchr(arg, '=') + sizeof(char), /*base=*/ 10));
            if(!DirectReader::SetChunkSize(size)) {
                S3FS_PRN_EXIT("direct_read_prefetch_chunk_size option must between 1 and 32.");
                return -1;
            }
            return 0;
        }
        if(is_prefix(arg, "direct_read_prefetch_chunks=")) {
            int count = static_cast<int>(cvt_strtoofft(strchr(arg, '=') + sizeof(char), /*base=*/10));
            if(!DirectReader::SetPrefetchChunkCount(count)) {
                return -1;
            }
            return 0;
        }
        if(is_prefix(arg, "direct_read_prefetch_limit=")) {
            long limit = static_cast<long>(cvt_strtoofft(strchr(arg, '=') + sizeof(char), /*base=*/ 10));
            if(!DirectReader::SetPrefetchCacheLimits(limit)) {
                S3FS_PRN_EXIT("prefetch_cache_limits option should be greater than 128.");
                return -1;
            }
            return 0;
        }
        if(is_prefix(arg, "direct_read_backward_chunks=")) {
            int count = static_cast<int>(cvt_strtoofft(strchr(arg, '=') + sizeof(char), /*base=*/10));
            if(!DirectReader::SetBackwardChunks(count)) {
                return -1;
            }
            return 0;
        }
        // takes effect only when direct_read == true
        if(is_prefix(arg, "direct_read_local_file_cache_size_mb=")) {
            long limit = static_cast<long>(cvt_strtoofft(strchr(arg, '=') + sizeof(char), /*base=*/ 10));
            if(!DirectReader::SetDirectReadLocalFileCacheSizeMB(limit)) {
                S3FS_PRN_EXIT("Invalid direct_read_local_file_cache_size_mb.");
                return -1;
            }
            return 0;
        }
        //
        // log file option
        //
        if(is_prefix(arg, "logfile=")){
            const char* strlogfile = strchr(arg, '=') + sizeof(char);
            if(!S3fsLog::SetLogfile(strlogfile)){
                S3FS_PRN_EXIT("The file(%s) specified by logfile option could not be opened.", strlogfile);
                return -1;
            }
            return 0;
        }
        //
        // debug level option
        //
        if(is_prefix(arg, "dbglevel=")){
            const char* strlevel = strchr(arg, '=') + sizeof(char);
            if(0 == strcasecmp(strlevel, "silent") || 0 == strcasecmp(strlevel, "critical") || 0 == strcasecmp(strlevel, "crit")){
                S3fsLog::SetLogLevel(S3fsLog::LEVEL_CRIT);
            }else if(0 == strcasecmp(strlevel, "error") || 0 == strcasecmp(strlevel, "err")){
                S3fsLog::SetLogLevel(S3fsLog::LEVEL_ERR);
            }else if(0 == strcasecmp(strlevel, "wan") || 0 == strcasecmp(strlevel, "warn") || 0 == strcasecmp(strlevel, "warning")){
                S3fsLog::SetLogLevel(S3fsLog::LEVEL_WARN);
            }else if(0 == strcasecmp(strlevel, "inf") || 0 == strcasecmp(strlevel, "info") || 0 == strcasecmp(strlevel, "information")){
                S3fsLog::SetLogLevel(S3fsLog::LEVEL_INFO);
            }else if(0 == strcasecmp(strlevel, "dbg") || 0 == strcasecmp(strlevel, "debug")){
                S3fsLog::SetLogLevel(S3fsLog::LEVEL_DBG);
            }else{
                S3FS_PRN_EXIT("option dbglevel has unknown parameter(%s).", strlevel);
                return -1;
            }
            return 0;
        }
        //
        // debug option
        //
        // S3fsLog level is LEVEL_INFO, after second -d is passed to fuse.
        //
        if(0 == strcmp(arg, "-d") || 0 == strcmp(arg, "--debug")){
            if(!S3fsLog::IsS3fsLogInfo() && !S3fsLog::IsS3fsLogDbg()){
                S3fsLog::SetLogLevel(S3fsLog::LEVEL_INFO);
                return 0;
            }
            if(0 == strcmp(arg, "--debug")){
                // fuse doesn't understand "--debug", but it understands -d.
                // but we can't pass -d back to fuse.
                return 0;
            }
        }
        // "f2" is not used no more.
        // (set S3fsLog::LEVEL_DBG)
        if(0 == strcmp(arg, "f2")){
            S3fsLog::SetLogLevel(S3fsLog::LEVEL_DBG);
            return 0;
        }
        if(0 == strcmp(arg, "curldbg")){
            S3fsCurl::SetVerbose(true);
            return 0;
        }else if(is_prefix(arg, "curldbg=")){
            const char* strlevel = strchr(arg, '=') + sizeof(char);
            if(0 == strcasecmp(strlevel, "normal")){
                S3fsCurl::SetVerbose(true);
            }else if(0 == strcasecmp(strlevel, "body")){
                S3fsCurl::SetVerbose(true);
                S3fsCurl::SetDumpBody(true);
            }else{
                S3FS_PRN_EXIT("option curldbg has unknown parameter(%s).", strlevel);
                return -1;
            }
            return 0;
        }
        //
        // no time stamp in debug message
        //
        if(0 == strcmp(arg, "no_time_stamp_msg")){
            S3fsLog::SetTimeStamp(false);
            return 0;
        }
        //
        // Check cache file, using SIGUSR1
        //
        if(0 == strcmp(arg, "set_check_cache_sigusr1")){
            if(!S3fsSignals::SetUsr1Handler(NULL)){
                S3FS_PRN_EXIT("could not set sigusr1 for checking cache.");
                return -1;
            }
            return 0;
        }else if(is_prefix(arg, "set_check_cache_sigusr1=")){
            const char* strfilepath = strchr(arg, '=') + sizeof(char);
            if(!S3fsSignals::SetUsr1Handler(strfilepath)){
                S3FS_PRN_EXIT("could not set sigusr1 for checking cache and output file(%s).", strfilepath);
                return -1;
            }
            return 0;
        }
        if(is_prefix(arg, "accessKeyId=")){
            S3FS_PRN_EXIT("option accessKeyId is no longer supported.");
            return -1;
        }
        if(is_prefix(arg, "secretAccessKey=")){
            S3FS_PRN_EXIT("option secretAccessKey is no longer supported.");
            return -1;
        }
        if(0 == strcmp(arg, "use_wtf8")){
            use_wtf8 = true;
            return 0;
        }
        if(0 == strcmp(arg, "requester_pays")){
            S3fsCurl::SetRequesterPays(true);
            return 0;
        }
        if(0 == strcmp(arg, "sigv4")){
            S3fsCurl::SetSignatureType(V4_ONLY);
            return 0;
        }
        if (is_prefix(arg, "cloudbox_id=")) {
            cloudbox_id = strchr(arg, '=') + sizeof(char);
            return 0;
        }
        if (is_prefix(arg, "region=")) {
            region              = strchr(arg, '=') + sizeof(char);
            is_specified_region = true;
            return 0;
        }
        // [NOTE]
        // following option will be discarding, because these are not for fuse.
        // (Referenced sshfs.c)
        //
        if(0 == strcmp(arg, "auto")   ||
           0 == strcmp(arg, "noauto") ||
           0 == strcmp(arg, "user")   ||
           0 == strcmp(arg, "nouser") ||
           0 == strcmp(arg, "users")  ||
           0 == strcmp(arg, "_netdev"))
        {
            return 0;
        }
    }
    return 1;
}