mirror of
https://github.com/samba-team/samba.git
synced 2024-12-23 17:34:34 +03:00
Add support for offline files support, remote storage, and Async I/O force operations to VFS
Offline files support and remote storage are for allowing communication with backup and archiving tools that mark files moved to a tape library as offline. We translate this info into corresponding CIFS offline file attribute and mark an exported volume as remote storage. Async I/O force is to allow selective redirection of I/O operations to asynchronous processing in case it is viable at VFS module discretion. It is needed for proper handling of offline files as performing regular I/O on offline file will block smbd. Signed-off-by: Alexander Bokovoy <ab@samba.org>
This commit is contained in:
parent
0c8e23afbb
commit
875208724e
@ -70,6 +70,7 @@
|
||||
* timestamp resolition. JRA. */
|
||||
/* Changed to version21 to add chflags operation -- jpeach */
|
||||
/* Changed to version22 to add lchown operation -- jra */
|
||||
/* Additional change: add operations for offline files and remote storage volume abstraction -- ab*/
|
||||
/* Leave at 22 - not yet released. But change set_nt_acl to return an NTSTATUS. jra. */
|
||||
/* Leave at 22 - not yet released. Add file_id_create operation. --metze */
|
||||
/* Leave at 22 - not yet released. Change all BOOL parameters (int) to bool. jra. */
|
||||
@ -257,6 +258,12 @@ typedef enum _vfs_op_type {
|
||||
SMB_VFS_OP_AIO_ERROR,
|
||||
SMB_VFS_OP_AIO_FSYNC,
|
||||
SMB_VFS_OP_AIO_SUSPEND,
|
||||
SMB_VFS_OP_AIO_FORCE,
|
||||
|
||||
/* offline operations */
|
||||
SMB_VFS_OP_IS_OFFLINE,
|
||||
SMB_VFS_OP_SET_OFFLINE,
|
||||
SMB_VFS_OP_IS_REMOTESTORAGE,
|
||||
|
||||
/* This should always be last enum value */
|
||||
|
||||
@ -405,6 +412,12 @@ struct vfs_ops {
|
||||
int (*aio_error_fn)(struct vfs_handle_struct *handle, struct files_struct *fsp, SMB_STRUCT_AIOCB *aiocb);
|
||||
int (*aio_fsync)(struct vfs_handle_struct *handle, struct files_struct *fsp, int op, SMB_STRUCT_AIOCB *aiocb);
|
||||
int (*aio_suspend)(struct vfs_handle_struct *handle, struct files_struct *fsp, const SMB_STRUCT_AIOCB * const aiocb[], int n, const struct timespec *timeout);
|
||||
bool (*aio_force)(struct vfs_handle_struct *handle, struct files_struct *fsp);
|
||||
|
||||
/* offline operations */
|
||||
int (*is_offline)(struct vfs_handle_struct *handle, struct connection_struct *conn, const char *path, SMB_STRUCT_STAT *sbuf, bool *offline);
|
||||
int (*set_offline)(struct vfs_handle_struct *handle, struct connection_struct *conn, const char *path);
|
||||
bool (*is_remotestorage)(struct vfs_handle_struct *handle, struct connection_struct *conn, const char *path);
|
||||
|
||||
} ops;
|
||||
|
||||
@ -526,6 +539,12 @@ struct vfs_ops {
|
||||
struct vfs_handle_struct *aio_error;
|
||||
struct vfs_handle_struct *aio_fsync;
|
||||
struct vfs_handle_struct *aio_suspend;
|
||||
struct vfs_handle_struct *aio_force;
|
||||
|
||||
/* offline operations */
|
||||
struct vfs_handle_struct *is_offline;
|
||||
struct vfs_handle_struct *set_offline;
|
||||
struct vfs_handle_struct *is_remotestorage;
|
||||
} handles;
|
||||
};
|
||||
|
||||
|
@ -138,6 +138,12 @@
|
||||
#define SMB_VFS_AIO_ERROR(fsp,aiocb) ((fsp)->conn->vfs.ops.aio_error_fn((fsp)->conn->vfs.handles.aio_error,(fsp),(aiocb)))
|
||||
#define SMB_VFS_AIO_FSYNC(fsp,op,aiocb) ((fsp)->conn->vfs.ops.aio_fsync((fsp)->conn->vfs.handles.aio_fsync,(fsp),(op),(aiocb)))
|
||||
#define SMB_VFS_AIO_SUSPEND(fsp,aiocb,n,ts) ((fsp)->conn->vfs.ops.aio_suspend((fsp)->conn->vfs.handles.aio_suspend,(fsp),(aiocb),(n),(ts)))
|
||||
#define SMB_VFS_AIO_FORCE(fsp) ((fsp)->conn->vfs.ops.aio_force((fsp)->conn->vfs.handles.aio_force,(fsp)))
|
||||
|
||||
/* Offline operations */
|
||||
#define SMB_VFS_IS_OFFLINE(conn,path,sbuf,offline) ((conn)->vfs.ops.is_offline((conn)->vfs.handles.is_offline,(conn),(path),(sbuf),(offline)))
|
||||
#define SMB_VFS_SET_OFFLINE(conn,path) ((conn)->vfs.ops.set_offline((conn)->vfs.handles.set_offline,(conn),(path)))
|
||||
#define SMB_VFS_IS_REMOTESTORAGE(conn,path) ((conn)->vfs.ops.is_remotestorage((conn)->vfs.handles.is_remotestorage,(conn),(path)))
|
||||
|
||||
/*******************************************************************
|
||||
Don't access conn->vfs_opaque.ops directly!!!
|
||||
@ -257,6 +263,12 @@
|
||||
#define SMB_VFS_OPAQUE_AIO_ERROR(fsp,aiocb) ((fsp)->conn->vfs_opaque.ops.aio_error_fn((fsp)->conn->vfs_opaque.handles.aio_error,(fsp),(aiocb)))
|
||||
#define SMB_VFS_OPAQUE_AIO_FSYNC(fsp,op,aiocb) ((fsp)->conn->vfs_opaque.ops.aio_fsync((fsp)->conn->vfs_opaque.handles.aio_fsync,(fsp),(op),(aiocb)))
|
||||
#define SMB_VFS_OPAQUE_AIO_SUSPEND(fsp,aiocb,n,ts) ((fsp)->conn->vfs_opaque.ops.aio_suspend((fsp)->conn->vfs_opaque.handles.aio_suspend,(fsp),(aiocb),(n),(ts)))
|
||||
#define SMB_VFS_OPAQUE_AIO_FORCE(fsp) ((fsp)->conn->vfs_opaque.ops.aio_force((fsp)->conn->vfs_opaque.handles.aio_force,(fsp)))
|
||||
|
||||
/* Offline operations */
|
||||
#define SMB_VFS_OPAQUE_IS_OFFLINE(conn,path,sbuf,offline) ((conn)->vfs_opaque.ops.is_offline((conn)->vfs_opaque.handles.is_offline,(conn),(path),(sbuf),(offline)))
|
||||
#define SMB_VFS_OPAQUE_SET_OFFLINE(conn,path) ((conn)->vfs_opaque.ops.set_offline((conn)->vfs_opaque.handles.set_offline,(conn),(path)))
|
||||
#define SMB_VFS_OPAQUE_IS_REMOTESTORAGE(conn,path) ((conn)->vfs_opaque.ops.is_remotestorage((conn)->vfs_opaque.handles.is_remotestorage,(conn),(path)))
|
||||
|
||||
/*******************************************************************
|
||||
Don't access handle->vfs_next.ops.* directly!!!
|
||||
@ -377,5 +389,11 @@
|
||||
#define SMB_VFS_NEXT_AIO_ERROR(handle,fsp,aiocb) ((handle)->vfs_next.ops.aio_error_fn((handle)->vfs_next.handles.aio_error,(fsp),(aiocb)))
|
||||
#define SMB_VFS_NEXT_AIO_FSYNC(handle,fsp,op,aiocb) ((handle)->vfs_next.ops.aio_fsync((handle)->vfs_next.handles.aio_fsync,(fsp),(op),(aiocb)))
|
||||
#define SMB_VFS_NEXT_AIO_SUSPEND(handle,fsp,aiocb,n,ts) ((handle)->vfs_next.ops.aio_suspend((handle)->vfs_next.handles.aio_suspend,(fsp),(aiocb),(n),(ts)))
|
||||
#define SMB_VFS_NEXT_AIO_FORCE(handle,fsp) ((handle)->vfs_next.ops.aio_force((handle)->vfs_next.handles.aio_force,(fsp)))
|
||||
|
||||
/* Offline operations */
|
||||
#define SMB_VFS_NEXT_IS_OFFLINE(conn,path,sbuf,offline) ((conn)->vfs_next.ops.is_offline((conn)->vfs_next.handles.is_offline,(conn),(path),(sbuf),(offline)))
|
||||
#define SMB_VFS_NEXT_SET_OFFLINE(conn,path) ((conn)->vfs_next.ops.set_offline((conn)->vfs_next.handles.set_offline,(conn),(path)))
|
||||
#define SMB_VFS_NEXT_IS_REMOTESTORAGE(conn,path) ((conn)->vfs_next.ops.is_remotestorage((conn)->vfs_next.handles.is_remotestorage,(conn),(path)))
|
||||
|
||||
#endif /* _VFS_MACROS_H */
|
||||
|
@ -1225,6 +1225,38 @@ static int vfswrap_aio_suspend(struct vfs_handle_struct *handle, struct files_st
|
||||
return sys_aio_suspend(aiocb, n, timeout);
|
||||
}
|
||||
|
||||
static int vfswrap_aio_force(struct vfs_handle_struct *handle, struct files_struct *fsp)
|
||||
{
|
||||
return False;
|
||||
}
|
||||
|
||||
static int vfswrap_is_offline(struct vfs_handle_struct *handle, struct connection_struct *conn, const char *path, SMB_STRUCT_STAT *sbuf, bool *offline)
|
||||
{
|
||||
if (ISDOT(path) || ISDOTDOT(path)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!lp_dmapi_support(SNUM(conn)) || !dmapi_have_session()) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
*offline = (dmapi_file_flags(path) & FILE_ATTRIBUTE_OFFLINE) != 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vfswrap_set_offline(struct vfs_handle_struct *handle, struct connection_struct *conn, const char *path)
|
||||
{
|
||||
/* We don't know how to set offline bit by default, needs to be overriden in the vfs modules */
|
||||
return -1;
|
||||
}
|
||||
|
||||
static bool vfswrap_is_remotestorage(struct vfs_handle_struct *handle, struct connection_struct *conn, const char *path)
|
||||
{
|
||||
/* We don't know how to detect that volume is remote storage. VFS modules should redefine it. */
|
||||
return False;
|
||||
}
|
||||
|
||||
|
||||
static vfs_op_tuple vfs_default_ops[] = {
|
||||
|
||||
/* Disk operations */
|
||||
@ -1442,6 +1474,16 @@ static vfs_op_tuple vfs_default_ops[] = {
|
||||
{SMB_VFS_OP(vfswrap_aio_suspend),SMB_VFS_OP_AIO_SUSPEND,
|
||||
SMB_VFS_LAYER_OPAQUE},
|
||||
|
||||
{SMB_VFS_OP(vfswrap_aio_force), SMB_VFS_OP_AIO_FORCE,
|
||||
SMB_VFS_LAYER_OPAQUE},
|
||||
|
||||
{SMB_VFS_OP(vfswrap_is_offline),SMB_VFS_OP_IS_OFFLINE,
|
||||
SMB_VFS_LAYER_OPAQUE},
|
||||
{SMB_VFS_OP(vfswrap_set_offline),SMB_VFS_OP_SET_OFFLINE,
|
||||
SMB_VFS_LAYER_OPAQUE},
|
||||
{SMB_VFS_OP(vfswrap_is_remotestorage),SMB_VFS_OP_IS_REMOTESTORAGE,
|
||||
SMB_VFS_LAYER_OPAQUE},
|
||||
|
||||
/* Finish VFS operations definition */
|
||||
|
||||
{SMB_VFS_OP(NULL), SMB_VFS_OP_NOOP,
|
||||
|
@ -46,7 +46,7 @@ bool dmapi_have_session(void) { return False; }
|
||||
#define DMAPI_SESSION_NAME "samba"
|
||||
#define DMAPI_TRACE 10
|
||||
|
||||
static dm_sessid_t dmapi_session = DM_NO_SESSION;
|
||||
static dm_sessid_t samba_dmapi_session = DM_NO_SESSION;
|
||||
|
||||
/* Initialise the DMAPI interface. Make sure that we only end up initialising
|
||||
* once per process to avoid resource leaks across different DMAPI
|
||||
@ -75,7 +75,7 @@ static int init_dmapi_service(void)
|
||||
|
||||
bool dmapi_have_session(void)
|
||||
{
|
||||
return dmapi_session != DM_NO_SESSION;
|
||||
return samba_dmapi_session != DM_NO_SESSION;
|
||||
}
|
||||
|
||||
static dm_sessid_t *realloc_session_list(dm_sessid_t * sessions, int count)
|
||||
@ -110,7 +110,7 @@ int dmapi_init_session(void)
|
||||
*/
|
||||
SMB_WARN(getuid() == 0, "dmapi_init_session must be called as root");
|
||||
|
||||
dmapi_session = DM_NO_SESSION;
|
||||
samba_dmapi_session = DM_NO_SESSION;
|
||||
if (init_dmapi_service() < 0) {
|
||||
return -1;
|
||||
}
|
||||
@ -139,7 +139,7 @@ retry:
|
||||
err = dm_query_session(sessions[i], sizeof(buf), buf, &buflen);
|
||||
buf[sizeof(buf) - 1] = '\0';
|
||||
if (err == 0 && strcmp(DMAPI_SESSION_NAME, buf) == 0) {
|
||||
dmapi_session = sessions[i];
|
||||
samba_dmapi_session = sessions[i];
|
||||
DEBUGADD(DMAPI_TRACE,
|
||||
("attached to existing DMAPI session "
|
||||
"named '%s'\n", buf));
|
||||
@ -150,16 +150,15 @@ retry:
|
||||
TALLOC_FREE(sessions);
|
||||
|
||||
/* No session already defined. */
|
||||
if (dmapi_session == DM_NO_SESSION) {
|
||||
err = dm_create_session(DM_NO_SESSION,
|
||||
CONST_DISCARD(char *,
|
||||
DMAPI_SESSION_NAME),
|
||||
&dmapi_session);
|
||||
if (samba_dmapi_session == DM_NO_SESSION) {
|
||||
err = dm_create_session(DM_NO_SESSION,
|
||||
CONST_DISCARD(char *, DMAPI_SESSION_NAME),
|
||||
&samba_dmapi_session);
|
||||
if (err < 0) {
|
||||
DEBUGADD(DMAPI_TRACE,
|
||||
("failed to create new DMAPI session: %s\n",
|
||||
strerror(errno)));
|
||||
dmapi_session = DM_NO_SESSION;
|
||||
samba_dmapi_session = DM_NO_SESSION;
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -185,22 +184,22 @@ static int reattach_dmapi_session(void)
|
||||
char buf[DM_SESSION_INFO_LEN];
|
||||
size_t buflen;
|
||||
|
||||
if (dmapi_session != DM_NO_SESSION ) {
|
||||
if (samba_dmapi_session != DM_NO_SESSION ) {
|
||||
become_root();
|
||||
|
||||
/* NOTE: On Linux, this call opens /dev/dmapi, costing us a
|
||||
* file descriptor. Ideally, we would close this when we fork.
|
||||
*/
|
||||
if (init_dmapi_service() < 0) {
|
||||
dmapi_session = DM_NO_SESSION;
|
||||
samba_dmapi_session = DM_NO_SESSION;
|
||||
unbecome_root();
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (dm_query_session(dmapi_session, sizeof(buf),
|
||||
if (dm_query_session(samba_dmapi_session, sizeof(buf),
|
||||
buf, &buflen) < 0) {
|
||||
/* Session is stale. Disable DMAPI. */
|
||||
dmapi_session = DM_NO_SESSION;
|
||||
samba_dmapi_session = DM_NO_SESSION;
|
||||
unbecome_root();
|
||||
return -1;
|
||||
}
|
||||
@ -214,33 +213,42 @@ static int reattach_dmapi_session(void)
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32 dmapi_file_flags(const char * const path)
|
||||
/* If a DMAPI session has been initialised, then we need to make sure
|
||||
* we are attached to it and have the correct privileges. This is
|
||||
* necessary to be able to do DMAPI operations across a fork(2). If
|
||||
* it fails, there is no likelihood of that failure being transient.
|
||||
*
|
||||
* Note that this use of the static attached flag relies on the fact
|
||||
* that dmapi_file_flags() is never called prior to forking the
|
||||
* per-client server process.
|
||||
*/
|
||||
const void * dmapi_get_current_session(void)
|
||||
{
|
||||
static int attached = 0;
|
||||
if (dmapi_have_session() && !attached) {
|
||||
attached++;
|
||||
if (reattach_dmapi_session() < 0) {
|
||||
return DM_NO_SESSION;
|
||||
}
|
||||
}
|
||||
return &samba_dmapi_session;
|
||||
}
|
||||
|
||||
uint32 dmapi_file_flags(const char * const path)
|
||||
{
|
||||
dm_sessid_t dmapi_session;
|
||||
int err;
|
||||
dm_eventset_t events = {0};
|
||||
uint nevents;
|
||||
|
||||
void *dm_handle;
|
||||
size_t dm_handle_len;
|
||||
void *dm_handle = NULL;
|
||||
size_t dm_handle_len = 0;
|
||||
|
||||
uint32 flags = 0;
|
||||
|
||||
/* If a DMAPI session has been initialised, then we need to make sure
|
||||
* we are attached to it and have the correct privileges. This is
|
||||
* necessary to be able to do DMAPI operations across a fork(2). If
|
||||
* it fails, there is no liklihood of that failure being transient.
|
||||
*
|
||||
* Note that this use of the static attached flag relies on the fact
|
||||
* that dmapi_file_flags() is never called prior to forking the
|
||||
* per-client server process.
|
||||
*/
|
||||
if (dmapi_have_session() && !attached) {
|
||||
attached++;
|
||||
if (reattach_dmapi_session() < 0) {
|
||||
return 0;
|
||||
}
|
||||
dmapi_session = *(dm_sessid_t*) dmapi_get_current_session();
|
||||
if (dmapi_session == DM_NO_SESSION) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* AIX has DMAPI but no POSIX capablities support. In this case,
|
||||
@ -313,4 +321,5 @@ done:
|
||||
return flags;
|
||||
}
|
||||
|
||||
|
||||
#endif /* USE_DMAPI */
|
||||
|
@ -30,23 +30,6 @@ static int set_sparse_flag(const SMB_STRUCT_STAT * const sbuf)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
Work out whether this file is offline
|
||||
****************************************************************************/
|
||||
|
||||
static uint32 set_offline_flag(connection_struct *conn, const char *const path)
|
||||
{
|
||||
if (ISDOT(path) || ISDOTDOT(path)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!lp_dmapi_support(SNUM(conn)) || !dmapi_have_session()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return dmapi_file_flags(path);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
Change a dos mode to a unix mode.
|
||||
Base permission for files:
|
||||
@ -366,6 +349,8 @@ uint32 dos_mode_msdfs(connection_struct *conn, const char *path,SMB_STRUCT_STAT
|
||||
uint32 dos_mode(connection_struct *conn, const char *path,SMB_STRUCT_STAT *sbuf)
|
||||
{
|
||||
uint32 result = 0;
|
||||
bool offline;
|
||||
int ret;
|
||||
|
||||
DEBUG(8,("dos_mode: %s\n", path));
|
||||
|
||||
@ -395,8 +380,10 @@ uint32 dos_mode(connection_struct *conn, const char *path,SMB_STRUCT_STAT *sbuf)
|
||||
result |= dos_mode_from_sbuf(conn, path, sbuf);
|
||||
}
|
||||
|
||||
if (S_ISREG(sbuf->st_mode)) {
|
||||
result |= set_offline_flag(conn, path);
|
||||
|
||||
ret = SMB_VFS_IS_OFFLINE(conn, path, sbuf, &offline);
|
||||
if (S_ISREG(sbuf->st_mode) && (ret == 0) && offline) {
|
||||
result |= FILE_ATTRIBUTE_OFFLINE;
|
||||
}
|
||||
|
||||
/* Optimization : Only call is_hidden_path if it's not already
|
||||
@ -432,7 +419,7 @@ int file_set_dosmode(connection_struct *conn, const char *fname,
|
||||
int mask=0;
|
||||
mode_t tmp;
|
||||
mode_t unixmode;
|
||||
int ret = -1;
|
||||
int ret = -1, lret = -1;
|
||||
|
||||
/* We only allow READONLY|HIDDEN|SYSTEM|DIRECTORY|ARCHIVE here. */
|
||||
dosmode &= SAMBA_ATTRIBUTES_MASK;
|
||||
@ -505,10 +492,21 @@ int file_set_dosmode(connection_struct *conn, const char *fname,
|
||||
unixmode |= (st->st_mode & (S_IWUSR|S_IWGRP|S_IWOTH));
|
||||
}
|
||||
|
||||
if ((ret = SMB_VFS_CHMOD(conn,fname,unixmode)) == 0) {
|
||||
if (!newfile) {
|
||||
if (dosmode & FILE_ATTRIBUTE_OFFLINE) {
|
||||
lret = SMB_VFS_SET_OFFLINE(conn, fname);
|
||||
if (lret == -1) {
|
||||
DEBUG(0, ("set_dos_mode: client has asked to set "
|
||||
"FILE_ATTRIBUTE_OFFLINE to %s/%s but there was "
|
||||
"an error while setting it or it is not supported.\n",
|
||||
parent_dir, fname));
|
||||
}
|
||||
}
|
||||
|
||||
ret = SMB_VFS_CHMOD(conn, fname, unixmode);
|
||||
if (ret == 0) {
|
||||
if(!newfile || (lret != -1)) {
|
||||
notify_fname(conn, NOTIFY_ACTION_MODIFIED,
|
||||
FILE_NOTIFY_CHANGE_ATTRIBUTES, fname);
|
||||
FILE_NOTIFY_CHANGE_ATTRIBUTES, fname);
|
||||
}
|
||||
st->st_mode = unixmode;
|
||||
return 0;
|
||||
|
@ -3329,8 +3329,12 @@ void reply_read_and_X(struct smb_request *req)
|
||||
return;
|
||||
}
|
||||
|
||||
if (!big_readX
|
||||
&& schedule_aio_read_and_X(conn, req, fsp, startpos, smb_maxcnt)) {
|
||||
/* It is possible for VFS modules to selectively decide whether Async I/O should be used
|
||||
for the file or not.
|
||||
*/
|
||||
if ((SMB_VFS_AIO_FORCE(fsp)) &&
|
||||
!big_readX &&
|
||||
schedule_aio_read_and_X(conn, req, fsp, startpos, smb_maxcnt)) {
|
||||
END_PROFILE(SMBreadX);
|
||||
return;
|
||||
}
|
||||
@ -4001,13 +4005,16 @@ void reply_write_and_X(struct smb_request *req)
|
||||
nwritten = 0;
|
||||
} else {
|
||||
|
||||
if (req->unread_bytes == 0 &&
|
||||
schedule_aio_write_and_X(conn, req, fsp, data,
|
||||
startpos, numtowrite)) {
|
||||
/* It is possible for VFS modules to selectively decide whether Async I/O
|
||||
should be used for the file or not.
|
||||
*/
|
||||
if ((SMB_VFS_AIO_FORCE(fsp)) && (req->unread_bytes == 0) &&
|
||||
schedule_aio_write_and_X(conn, req, fsp, data, startpos,
|
||||
numtowrite)) {
|
||||
END_PROFILE(SMBwriteX);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
nwritten = write_file(req,fsp,data,startpos,numtowrite);
|
||||
}
|
||||
|
||||
|
@ -2373,8 +2373,8 @@ static void call_trans2qfsinfo(connection_struct *conn,
|
||||
const char *vname = volume_label(SNUM(conn));
|
||||
int snum = SNUM(conn);
|
||||
char *fstype = lp_fstype(SNUM(conn));
|
||||
int quota_flag = 0;
|
||||
|
||||
uint32 additional_flags = 0;
|
||||
|
||||
if (total_params < 2) {
|
||||
reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
|
||||
return;
|
||||
@ -2487,16 +2487,23 @@ cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)st.st_dev, (unsi
|
||||
case SMB_QUERY_FS_ATTRIBUTE_INFO:
|
||||
case SMB_FS_ATTRIBUTE_INFORMATION:
|
||||
|
||||
|
||||
additional_flags = 0;
|
||||
#if defined(HAVE_SYS_QUOTAS)
|
||||
quota_flag = FILE_VOLUME_QUOTAS;
|
||||
additional_flags |= FILE_VOLUME_QUOTAS;
|
||||
#endif
|
||||
|
||||
if(lp_nt_acl_support(SNUM(conn))) {
|
||||
additional_flags |= FILE_PERSISTENT_ACLS;
|
||||
}
|
||||
|
||||
if(SMB_VFS_IS_REMOTESTORAGE(conn, lp_pathname(SNUM(conn)))) {
|
||||
additional_flags |= FILE_SUPPORTS_REMOTE_STORAGE;
|
||||
additional_flags |= FILE_SUPPORTS_REPARSE_POINTS;
|
||||
}
|
||||
|
||||
SIVAL(pdata,0,FILE_CASE_PRESERVED_NAMES|FILE_CASE_SENSITIVE_SEARCH|
|
||||
(lp_nt_acl_support(SNUM(conn)) ? FILE_PERSISTENT_ACLS : 0)|
|
||||
FILE_SUPPORTS_OBJECT_IDS|
|
||||
FILE_UNICODE_ON_DISK|
|
||||
quota_flag); /* FS ATTRIBUTES */
|
||||
FILE_SUPPORTS_OBJECT_IDS|FILE_UNICODE_ON_DISK|
|
||||
additional_flags); /* FS ATTRIBUTES */
|
||||
|
||||
SIVAL(pdata,4,255); /* Max filename component length */
|
||||
/* NOTE! the fstype must *not* be null terminated or win98 won't recognise it
|
||||
|
Loading…
Reference in New Issue
Block a user