summaryrefslogtreecommitdiff
path: root/source3
diff options
context:
space:
mode:
Diffstat (limited to 'source3')
-rw-r--r--source3/include/vfs.h19
-rw-r--r--source3/include/vfs_macros.h18
-rw-r--r--source3/modules/vfs_default.c42
-rw-r--r--source3/smbd/dmapi.c71
-rw-r--r--source3/smbd/dosmode.c44
-rw-r--r--source3/smbd/reply.c19
-rw-r--r--source3/smbd/trans2.c23
7 files changed, 168 insertions, 68 deletions
diff --git a/source3/include/vfs.h b/source3/include/vfs.h
index 0be3886227..be3cd91520 100644
--- a/source3/include/vfs.h
+++ b/source3/include/vfs.h
@@ -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;
};
diff --git a/source3/include/vfs_macros.h b/source3/include/vfs_macros.h
index 9232e94a42..dbba781377 100644
--- a/source3/include/vfs_macros.h
+++ b/source3/include/vfs_macros.h
@@ -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 */
diff --git a/source3/modules/vfs_default.c b/source3/modules/vfs_default.c
index e21136ccee..3e78c69a5e 100644
--- a/source3/modules/vfs_default.c
+++ b/source3/modules/vfs_default.c
@@ -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,
diff --git a/source3/smbd/dmapi.c b/source3/smbd/dmapi.c
index 05e9138ea9..620baf199e 100644
--- a/source3/smbd/dmapi.c
+++ b/source3/smbd/dmapi.c
@@ -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 */
diff --git a/source3/smbd/dosmode.c b/source3/smbd/dosmode.c
index d3813f9b41..2021621dfa 100644
--- a/source3/smbd/dosmode.c
+++ b/source3/smbd/dosmode.c
@@ -31,23 +31,6 @@ static int set_sparse_flag(const SMB_STRUCT_STAT * const sbuf)
}
/****************************************************************************
- 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:
if creating file and inheriting (i.e. parent_dir != NULL)
@@ -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;
diff --git a/source3/smbd/reply.c b/source3/smbd/reply.c
index e2316ef120..381ddfe151 100644
--- a/source3/smbd/reply.c
+++ b/source3/smbd/reply.c
@@ -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);
}
diff --git a/source3/smbd/trans2.c b/source3/smbd/trans2.c
index bf6802f2a6..5729ab5349 100644
--- a/source3/smbd/trans2.c
+++ b/source3/smbd/trans2.c
@@ -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