2 * Copyright (C) 2021 SUSE LINUX GmbH
4 * This is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License version 2.1, as published by the Free Software
7 * Foundation. See file COPYING.
12 #include "include/compat.h"
13 #include "include/cephfs/libcephfs.h"
15 #include "ceph_dokan.h"
18 #include "common/ceph_argparse.h"
19 #include "common/config.h"
20 #include "common/win32/wstring.h"
22 #include "global/global_init.h"
25 const char* usage_str
= R
"(
26 Usage: ceph-dokan.exe -l <mountpoint>
27 map -l <mountpoint> Map a CephFS filesystem
28 unmap -l <mountpoint> Unmap a CephFS filesystem
31 -l [ --mountpoint ] arg mountpoint (path or drive letter) (e.g -l x)
32 -x [ --root-path ] arg mount a Ceph filesystem subdirectory
34 --operation-timeout arg Dokan operation timeout. Default: 120s.
36 --debug enable debug output
37 --dokan-stderr enable stderr Dokan logging
39 --read-only read-only mount
40 -o [ --win-mount-mgr] use the Windows mount manager
41 --current-session-only expose the mount only to the current user session
42 --removable use a removable drive
43 --win-vol-name arg The Windows volume name. Default: Ceph - <fs_name>.
44 --win-vol-serial arg The Windows volume serial number. Default: <fs_id>.
45 --max-path-len The value of the maximum path length. Default: 256.
46 --file-mode The access mode to be used when creating files.
47 --dir-mode The access mode to be used when creating directories.
50 -l [ --mountpoint ] arg mountpoint (path or drive letter) (e.g -l x).
51 It has to be the exact same mountpoint that was
52 used when the mapping was created.
57 std::cout
<< usage_str
;
58 generic_client_usage();
63 std::vector
<const char*>& args
,
64 std::ostream
*err_msg
,
65 Command
*command
, Config
*cfg
)
68 std::cout
<< "ceph-dokan: -h or --help for usage" << std::endl
;
72 std::string conf_file_list
;
74 CephInitParameters iparams
= ceph_argparse_early_args(
75 args
, CEPH_ENTITY_TYPE_CLIENT
, &cluster
, &conf_file_list
);
77 ConfigProxy config
{false};
78 config
->name
= iparams
.name
;
79 config
->cluster
= cluster
;
80 if (!conf_file_list
.empty()) {
81 config
.parse_config_files(conf_file_list
.c_str(), nullptr, 0);
83 config
.parse_config_files(nullptr, nullptr, 0);
85 config
.parse_env(CEPH_ENTITY_TYPE_CLIENT
);
86 config
.parse_argv(args
);
88 std::vector
<const char*>::iterator i
;
89 std::ostringstream err
;
90 std::string mountpoint
;
91 std::string win_vol_name
;
92 std::string win_vol_serial
;
93 std::string max_path_len
;
94 std::string file_mode
;
99 for (i
= args
.begin(); i
!= args
.end(); ) {
100 if (ceph_argparse_flag(args
, i
, "-h", "--help", (char*)NULL
)) {
101 *command
= Command::Help
;
103 } else if (ceph_argparse_flag(args
, i
, "-v", "--version", (char*)NULL
)) {
104 *command
= Command::Version
;
105 } else if (ceph_argparse_witharg(args
, i
, &mountpoint
,
106 "--mountpoint", "-l", (char *)NULL
)) {
107 cfg
->mountpoint
= to_wstring(mountpoint
);
108 } else if (ceph_argparse_witharg(args
, i
, &cfg
->root_path
,
109 "--root-path", "-x", (char *)NULL
)) {
110 } else if (ceph_argparse_flag(args
, i
, "--debug", (char *)NULL
)) {
112 } else if (ceph_argparse_flag(args
, i
, "--dokan-stderr", (char *)NULL
)) {
113 cfg
->dokan_stderr
= true;
114 } else if (ceph_argparse_flag(args
, i
, "--read-only", (char *)NULL
)) {
115 cfg
->readonly
= true;
116 } else if (ceph_argparse_flag(args
, i
, "--removable", (char *)NULL
)) {
117 cfg
->removable
= true;
118 } else if (ceph_argparse_flag(args
, i
, "--win-mount-mgr", "-o", (char *)NULL
)) {
119 cfg
->use_win_mount_mgr
= true;
120 } else if (ceph_argparse_witharg(args
, i
, &win_vol_name
,
121 "--win-vol-name", (char *)NULL
)) {
122 cfg
->win_vol_name
= to_wstring(win_vol_name
);
123 } else if (ceph_argparse_witharg(args
, i
, &win_vol_serial
,
124 "--win-vol-serial", (char *)NULL
)) {
125 cfg
->win_vol_serial
= std::stoul(win_vol_serial
);
126 } else if (ceph_argparse_witharg(args
, i
, &max_path_len
,
127 "--max-path-len", (char*)NULL
)) {
128 unsigned long max_path_length
= std::stoul(max_path_len
);
130 if (max_path_length
> 32767) {
131 *err_msg
<< "ceph-dokan: maximum path length should not "
132 << "exceed " << 32767;
136 if (max_path_length
< 256) {
137 *err_msg
<< "ceph-dokan: maximum path length should not "
138 << "have a value lower than 256";
142 cfg
->max_path_len
= max_path_length
;
143 } else if (ceph_argparse_witharg(args
, i
, &file_mode
, "--file-mode", (char *)NULL
)) {
144 mode_t mode
= strtol(file_mode
.c_str(), NULL
, 8);
145 if (!std::regex_match(file_mode
, std::regex("^[0-7]{3}$"))
146 || mode
< 01 || mode
> 0777) {
147 *err_msg
<< "ceph-dokan: invalid file access mode";
150 cfg
->file_mode
= mode
;
151 } else if (ceph_argparse_witharg(args
, i
, &dir_mode
, "--dir-mode", (char *)NULL
)) {
152 mode_t mode
= strtol(dir_mode
.c_str(), NULL
, 8);
153 if (!std::regex_match(dir_mode
, std::regex("^[0-7]{3}$"))
154 || mode
< 01 || mode
> 0777) {
155 *err_msg
<< "ceph-dokan: invalid directory access mode";
158 cfg
->dir_mode
= mode
;
159 } else if (ceph_argparse_flag(args
, i
, "--current-session-only", (char *)NULL
)) {
160 cfg
->current_session_only
= true;
161 } else if (ceph_argparse_witharg(args
, i
, &thread_count
,
162 err
, "--thread-count", "-t", (char *)NULL
)) {
163 std::cerr
<< "ceph-dokan: the thread count parameter is not supported by Dokany v2 "
164 << "and has been deprecated." << std::endl
;
165 } else if (ceph_argparse_witharg(args
, i
, (int*)&cfg
->operation_timeout
,
166 err
, "--operation-timeout", (char *)NULL
)) {
167 if (!err
.str().empty()) {
168 *err_msg
<< "ceph-dokan: " << err
.str();
171 if (cfg
->operation_timeout
< 0) {
172 *err_msg
<< "ceph-dokan: Invalid argument for operation-timeout";
180 if (cfg
->use_win_mount_mgr
&& cfg
->current_session_only
) {
181 *err_msg
<< "ceph-dokan: The mount manager always mounts the drive "
182 << "for all user sessions.";
186 Command cmd
= Command::None
;
187 if (args
.begin() != args
.end()) {
188 if (strcmp(*args
.begin(), "help") == 0) {
190 } else if (strcmp(*args
.begin(), "version") == 0) {
191 cmd
= Command::Version
;
192 } else if (strcmp(*args
.begin(), "map") == 0) {
194 } else if (strcmp(*args
.begin(), "unmap") == 0) {
195 cmd
= Command::Unmap
;
197 *err_msg
<< "ceph-dokan: unknown command: " << *args
.begin();
200 args
.erase(args
.begin());
202 if (cmd
== Command::None
) {
203 // The default command.
210 if (cfg
->mountpoint
.empty()) {
211 *err_msg
<< "ceph-dokan: missing mountpoint.";
219 if (args
.begin() != args
.end()) {
220 *err_msg
<< "ceph-dokan: unknown args: " << *args
.begin();
228 int set_dokan_options(Config
*cfg
, PDOKAN_OPTIONS dokan_options
) {
229 ZeroMemory(dokan_options
, sizeof(DOKAN_OPTIONS
));
230 dokan_options
->Version
= DOKAN_VERSION
;
231 dokan_options
->MountPoint
= cfg
->mountpoint
.c_str();
232 dokan_options
->Timeout
= cfg
->operation_timeout
* 1000;
235 dokan_options
->Options
|= DOKAN_OPTION_REMOVABLE
;
236 if (cfg
->use_win_mount_mgr
)
237 dokan_options
->Options
|= DOKAN_OPTION_MOUNT_MANAGER
;
238 if (cfg
->current_session_only
)
239 dokan_options
->Options
|= DOKAN_OPTION_CURRENT_SESSION
;
241 dokan_options
->Options
|= DOKAN_OPTION_WRITE_PROTECT
;
243 dokan_options
->Options
|= DOKAN_OPTION_DEBUG
;
244 if (cfg
->dokan_stderr
)
245 dokan_options
->Options
|= DOKAN_OPTION_STDERR
;