111963SAfshin.Ardakani@Sun.COM /*
211963SAfshin.Ardakani@Sun.COM * CDDL HEADER START
311963SAfshin.Ardakani@Sun.COM *
411963SAfshin.Ardakani@Sun.COM * The contents of this file are subject to the terms of the
511963SAfshin.Ardakani@Sun.COM * Common Development and Distribution License (the "License").
611963SAfshin.Ardakani@Sun.COM * You may not use this file except in compliance with the License.
711963SAfshin.Ardakani@Sun.COM *
811963SAfshin.Ardakani@Sun.COM * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
911963SAfshin.Ardakani@Sun.COM * or http://www.opensolaris.org/os/licensing.
1011963SAfshin.Ardakani@Sun.COM * See the License for the specific language governing permissions
1111963SAfshin.Ardakani@Sun.COM * and limitations under the License.
1211963SAfshin.Ardakani@Sun.COM *
1311963SAfshin.Ardakani@Sun.COM * When distributing Covered Code, include this CDDL HEADER in each
1411963SAfshin.Ardakani@Sun.COM * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1511963SAfshin.Ardakani@Sun.COM * If applicable, add the following below this CDDL HEADER, with the
1611963SAfshin.Ardakani@Sun.COM * fields enclosed by brackets "[]" replaced with your own identifying
1711963SAfshin.Ardakani@Sun.COM * information: Portions Copyright [yyyy] [name of copyright owner]
1811963SAfshin.Ardakani@Sun.COM *
1911963SAfshin.Ardakani@Sun.COM * CDDL HEADER END
2011963SAfshin.Ardakani@Sun.COM */
2112508Samw@Sun.COM
2211963SAfshin.Ardakani@Sun.COM /*
2312508Samw@Sun.COM * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
2411963SAfshin.Ardakani@Sun.COM */
2511963SAfshin.Ardakani@Sun.COM
2611963SAfshin.Ardakani@Sun.COM #include <strings.h>
2711963SAfshin.Ardakani@Sun.COM #include <errno.h>
2811963SAfshin.Ardakani@Sun.COM #include <unistd.h>
2911963SAfshin.Ardakani@Sun.COM #include <fcntl.h>
3011963SAfshin.Ardakani@Sun.COM #include <dirent.h>
3112508Samw@Sun.COM #include <dlfcn.h>
3211963SAfshin.Ardakani@Sun.COM #include <pthread.h>
3311963SAfshin.Ardakani@Sun.COM #include <syslog.h>
3411963SAfshin.Ardakani@Sun.COM #include <sys/fs_reparse.h>
3511963SAfshin.Ardakani@Sun.COM #include <uuid/uuid.h>
3611963SAfshin.Ardakani@Sun.COM
3712508Samw@Sun.COM #include <smbsrv/libsmb.h>
3812508Samw@Sun.COM #include <smbsrv/libmlsvc.h>
3911963SAfshin.Ardakani@Sun.COM #include <smbsrv/smb_dfs.h>
4011963SAfshin.Ardakani@Sun.COM #include <smbsrv/smb_share.h>
4111963SAfshin.Ardakani@Sun.COM #include <dfs.h>
4211963SAfshin.Ardakani@Sun.COM
4311963SAfshin.Ardakani@Sun.COM /*
4411963SAfshin.Ardakani@Sun.COM * default timeout (TTL) values (in second) for root and link
4511963SAfshin.Ardakani@Sun.COM */
4611963SAfshin.Ardakani@Sun.COM #define DFS_ROOT_TIMEOUT 300
4711963SAfshin.Ardakani@Sun.COM #define DFS_LINK_TIMEOUT 1800
4811963SAfshin.Ardakani@Sun.COM
4911963SAfshin.Ardakani@Sun.COM /*
5011963SAfshin.Ardakani@Sun.COM * DFS link data format in reparse point
5111963SAfshin.Ardakani@Sun.COM *
5211963SAfshin.Ardakani@Sun.COM * ver:state:prop:timeout:guid:ntarget:cmntlen:comment
5311963SAfshin.Ardakani@Sun.COM * [[:tserver:tshare:tstate:pclass:prank]...]
5411963SAfshin.Ardakani@Sun.COM */
5511963SAfshin.Ardakani@Sun.COM #define DFS_LINK_V1 1
5611963SAfshin.Ardakani@Sun.COM #define DFS_LINK_HDR_NFIELDS 7 /* # fields in header section */
5711963SAfshin.Ardakani@Sun.COM #define DFS_LINK_TRGT_NFIELDS 5 /* # fields for each target */
5811963SAfshin.Ardakani@Sun.COM
5911963SAfshin.Ardakani@Sun.COM #define DFS_ROOT_XATTR "SUNWdfs.rootinfo"
6011963SAfshin.Ardakani@Sun.COM
6111963SAfshin.Ardakani@Sun.COM #define DFS_INFO_ALL 0
6211963SAfshin.Ardakani@Sun.COM
6312508Samw@Sun.COM static void *dfs_intr_hdl = NULL;
6412508Samw@Sun.COM
6512508Samw@Sun.COM static struct {
6612508Samw@Sun.COM int (*dfsops_remote_count)(uint32_t *);
6712508Samw@Sun.COM } dfs_intr_ops;
6812508Samw@Sun.COM
6911963SAfshin.Ardakani@Sun.COM /*
7011963SAfshin.Ardakani@Sun.COM * Namespace cache
7111963SAfshin.Ardakani@Sun.COM *
7211963SAfshin.Ardakani@Sun.COM * Caches links' UNC and filesystem path where the key is the UNC path.
7311963SAfshin.Ardakani@Sun.COM */
7411963SAfshin.Ardakani@Sun.COM static smb_cache_t dfs_nscache;
7511963SAfshin.Ardakani@Sun.COM static char dfs_nbname[NETBIOS_NAME_SZ];
7611963SAfshin.Ardakani@Sun.COM
7711963SAfshin.Ardakani@Sun.COM /*
78*12890SJoyce.McIntosh@Sun.COM * The name of cached namespace. This will be the only
79*12890SJoyce.McIntosh@Sun.COM * exported namespace until hosting multiple namespaces
80*12890SJoyce.McIntosh@Sun.COM * is supported
81*12890SJoyce.McIntosh@Sun.COM */
82*12890SJoyce.McIntosh@Sun.COM static char dfs_cached_ns[MAXNAMELEN];
83*12890SJoyce.McIntosh@Sun.COM static mutex_t dfs_nsmtx;
84*12890SJoyce.McIntosh@Sun.COM
85*12890SJoyce.McIntosh@Sun.COM /*
8611963SAfshin.Ardakani@Sun.COM * Lock for accessing root information (extended attribute)
8711963SAfshin.Ardakani@Sun.COM */
8811963SAfshin.Ardakani@Sun.COM static rwlock_t dfs_root_rwl;
8911963SAfshin.Ardakani@Sun.COM
9011963SAfshin.Ardakani@Sun.COM extern uint32_t srvsvc_shr_setdfsroot(smb_share_t *, boolean_t);
9111963SAfshin.Ardakani@Sun.COM
9211963SAfshin.Ardakani@Sun.COM /*
9311963SAfshin.Ardakani@Sun.COM * Namespace functions
9411963SAfshin.Ardakani@Sun.COM */
9511963SAfshin.Ardakani@Sun.COM static boolean_t dfs_namespace_findlink(const char *, char *, char *, size_t);
9611963SAfshin.Ardakani@Sun.COM static void *dfs_namespace_cache(void *);
97*12890SJoyce.McIntosh@Sun.COM static boolean_t dfs_namespace_iscached(const char *);
9811963SAfshin.Ardakani@Sun.COM
9911963SAfshin.Ardakani@Sun.COM /*
10011963SAfshin.Ardakani@Sun.COM * Root functions
10111963SAfshin.Ardakani@Sun.COM */
10211963SAfshin.Ardakani@Sun.COM static int dfs_root_add(const char *, dfs_info_t *);
10311963SAfshin.Ardakani@Sun.COM static uint32_t dfs_root_remove(const char *);
10411963SAfshin.Ardakani@Sun.COM static uint32_t dfs_root_encode(dfs_info_t *, char **, size_t *);
10511963SAfshin.Ardakani@Sun.COM static uint32_t dfs_root_decode(dfs_info_t *, char *, size_t, uint32_t);
10611963SAfshin.Ardakani@Sun.COM static uint32_t dfs_root_isvalidstate(uint32_t);
10711963SAfshin.Ardakani@Sun.COM
10811963SAfshin.Ardakani@Sun.COM static int dfs_root_xopen(const char *, int);
10911963SAfshin.Ardakani@Sun.COM static void dfs_root_xclose(int);
11011963SAfshin.Ardakani@Sun.COM static uint32_t dfs_root_xwrite(int, dfs_info_t *);
11111963SAfshin.Ardakani@Sun.COM static uint32_t dfs_root_xread(int, dfs_info_t *, uint32_t);
11211963SAfshin.Ardakani@Sun.COM
11311963SAfshin.Ardakani@Sun.COM /*
11411963SAfshin.Ardakani@Sun.COM * Link functions
11511963SAfshin.Ardakani@Sun.COM */
11611963SAfshin.Ardakani@Sun.COM static uint32_t dfs_link_encode(dfs_info_t *, char *, size_t);
11711963SAfshin.Ardakani@Sun.COM static uint32_t dfs_link_decode(dfs_info_t *, char *, uint32_t);
11811963SAfshin.Ardakani@Sun.COM static uint32_t dfs_link_commit(const char *, dfs_info_t *);
11911963SAfshin.Ardakani@Sun.COM static boolean_t dfs_link_isvalidstate(uint32_t);
12011963SAfshin.Ardakani@Sun.COM
12111963SAfshin.Ardakani@Sun.COM /*
12211963SAfshin.Ardakani@Sun.COM * Target functions
12311963SAfshin.Ardakani@Sun.COM */
12411963SAfshin.Ardakani@Sun.COM static void dfs_target_init(dfs_target_t *, const char *, const char *,
12511963SAfshin.Ardakani@Sun.COM uint32_t);
12611963SAfshin.Ardakani@Sun.COM static int dfs_target_find(dfs_target_t *, uint32_t, const char *,
12711963SAfshin.Ardakani@Sun.COM const char *);
12811963SAfshin.Ardakani@Sun.COM static boolean_t dfs_target_isvalidstate(uint32_t);
12911963SAfshin.Ardakani@Sun.COM
13011963SAfshin.Ardakani@Sun.COM /*
13111963SAfshin.Ardakani@Sun.COM * Cache functions
13211963SAfshin.Ardakani@Sun.COM */
13311963SAfshin.Ardakani@Sun.COM static uint32_t dfs_cache_add_byunc(const char *, const char *, uint32_t);
13411963SAfshin.Ardakani@Sun.COM static void dfs_cache_populate(const char *, const char *);
13511963SAfshin.Ardakani@Sun.COM static int dfs_cache_cmp(const void *, const void *);
136*12890SJoyce.McIntosh@Sun.COM static void dfs_cache_flush(const char *);
137*12890SJoyce.McIntosh@Sun.COM static uint32_t dfs_cache_nscount(void);
13811963SAfshin.Ardakani@Sun.COM
13911963SAfshin.Ardakani@Sun.COM /*
14011963SAfshin.Ardakani@Sun.COM * Utility functions
14111963SAfshin.Ardakani@Sun.COM */
14211963SAfshin.Ardakani@Sun.COM static boolean_t dfs_path_isdir(const char *);
14311963SAfshin.Ardakani@Sun.COM static uint32_t dfs_modinfo(uint32_t, dfs_info_t *, dfs_info_t *, uint32_t);
14411963SAfshin.Ardakani@Sun.COM
14511963SAfshin.Ardakani@Sun.COM /*
14611963SAfshin.Ardakani@Sun.COM * DFS module initializationr:
14711963SAfshin.Ardakani@Sun.COM *
14811963SAfshin.Ardakani@Sun.COM * - creates the namespace cache
14911963SAfshin.Ardakani@Sun.COM * - gets system's NetBIOS name
15011963SAfshin.Ardakani@Sun.COM */
15111963SAfshin.Ardakani@Sun.COM void
dfs_init(void)15211963SAfshin.Ardakani@Sun.COM dfs_init(void)
15311963SAfshin.Ardakani@Sun.COM {
15411963SAfshin.Ardakani@Sun.COM smb_domain_t di;
15511963SAfshin.Ardakani@Sun.COM
15611963SAfshin.Ardakani@Sun.COM smb_cache_create(&dfs_nscache, 0, dfs_cache_cmp, free, bcopy,
15711963SAfshin.Ardakani@Sun.COM sizeof (dfs_nscnode_t));
15811963SAfshin.Ardakani@Sun.COM
15911963SAfshin.Ardakani@Sun.COM if (!smb_domain_lookup_type(SMB_DOMAIN_LOCAL, &di))
16011963SAfshin.Ardakani@Sun.COM return;
16111963SAfshin.Ardakani@Sun.COM
16211963SAfshin.Ardakani@Sun.COM (void) strlcpy(dfs_nbname, di.di_nbname, NETBIOS_NAME_SZ);
16312508Samw@Sun.COM
16412508Samw@Sun.COM bzero((void *)&dfs_intr_ops, sizeof (dfs_intr_ops));
16512508Samw@Sun.COM
16612508Samw@Sun.COM if ((dfs_intr_hdl = smb_dlopen()) == NULL)
16712508Samw@Sun.COM return;
16812508Samw@Sun.COM
16912508Samw@Sun.COM if ((dfs_intr_ops.dfsops_remote_count =
17012508Samw@Sun.COM (int (*)())dlsym(dfs_intr_hdl, "smb_dfs_remote_count")) == NULL) {
17112508Samw@Sun.COM smb_dlclose(dfs_intr_hdl);
17212508Samw@Sun.COM dfs_intr_hdl = NULL;
17312508Samw@Sun.COM bzero((void *)&dfs_intr_ops, sizeof (dfs_intr_ops));
17412508Samw@Sun.COM }
17511963SAfshin.Ardakani@Sun.COM }
17611963SAfshin.Ardakani@Sun.COM
17711963SAfshin.Ardakani@Sun.COM /*
17811963SAfshin.Ardakani@Sun.COM * DFS module cleanup:
17911963SAfshin.Ardakani@Sun.COM *
18011963SAfshin.Ardakani@Sun.COM * - destroys the namespace cache
18111963SAfshin.Ardakani@Sun.COM */
18211963SAfshin.Ardakani@Sun.COM void
dfs_fini(void)18311963SAfshin.Ardakani@Sun.COM dfs_fini(void)
18411963SAfshin.Ardakani@Sun.COM {
18512508Samw@Sun.COM smb_dlclose(dfs_intr_hdl);
18611963SAfshin.Ardakani@Sun.COM smb_cache_destroy(&dfs_nscache);
18711963SAfshin.Ardakani@Sun.COM }
18811963SAfshin.Ardakani@Sun.COM
18911963SAfshin.Ardakani@Sun.COM /*
19011963SAfshin.Ardakani@Sun.COM * To successfully handle some of link/root requests, some
19111963SAfshin.Ardakani@Sun.COM * file system operations need to be performed. These operations
19211963SAfshin.Ardakani@Sun.COM * should take place on behalf of the connected user (typically
19311963SAfshin.Ardakani@Sun.COM * Administrator) and to do so we need to have an infrastructure
19411963SAfshin.Ardakani@Sun.COM * in place so that smbd can act as a client and sends request to
19511963SAfshin.Ardakani@Sun.COM * the kernel. Right now, we lack this infrastructure, so we make
19611963SAfshin.Ardakani@Sun.COM * a compromise by temporarily enabling some privileges for smbd
19711963SAfshin.Ardakani@Sun.COM * to be able to fulfill various link/root requests.
19811963SAfshin.Ardakani@Sun.COM */
19911963SAfshin.Ardakani@Sun.COM void
dfs_setpriv(priv_op_t op)20011963SAfshin.Ardakani@Sun.COM dfs_setpriv(priv_op_t op)
20111963SAfshin.Ardakani@Sun.COM {
20211963SAfshin.Ardakani@Sun.COM (void) priv_set(op, PRIV_EFFECTIVE,
20311963SAfshin.Ardakani@Sun.COM PRIV_FILE_DAC_READ,
20411963SAfshin.Ardakani@Sun.COM PRIV_FILE_DAC_WRITE,
20511963SAfshin.Ardakani@Sun.COM PRIV_FILE_DAC_EXECUTE,
20611963SAfshin.Ardakani@Sun.COM PRIV_FILE_DAC_SEARCH, NULL);
20711963SAfshin.Ardakani@Sun.COM }
20811963SAfshin.Ardakani@Sun.COM
20911963SAfshin.Ardakani@Sun.COM /*
21011963SAfshin.Ardakani@Sun.COM * ========================
21111963SAfshin.Ardakani@Sun.COM * Namespace API (public)
21211963SAfshin.Ardakani@Sun.COM * ========================
21311963SAfshin.Ardakani@Sun.COM */
21411963SAfshin.Ardakani@Sun.COM
21511963SAfshin.Ardakani@Sun.COM /*
21611963SAfshin.Ardakani@Sun.COM * Launches a thread to cache the specified namespace
21711963SAfshin.Ardakani@Sun.COM */
21811963SAfshin.Ardakani@Sun.COM void
dfs_namespace_load(const char * name)21911963SAfshin.Ardakani@Sun.COM dfs_namespace_load(const char *name)
22011963SAfshin.Ardakani@Sun.COM {
22111963SAfshin.Ardakani@Sun.COM pthread_t thr;
22211963SAfshin.Ardakani@Sun.COM pthread_attr_t tattr;
22311963SAfshin.Ardakani@Sun.COM char *rootshr;
22411963SAfshin.Ardakani@Sun.COM int rc;
22511963SAfshin.Ardakani@Sun.COM
22611963SAfshin.Ardakani@Sun.COM if ((rootshr = strdup(name)) == NULL) {
22711963SAfshin.Ardakani@Sun.COM syslog(LOG_ERR, "dfs: failed to load %s namespace (no memory)",
22811963SAfshin.Ardakani@Sun.COM name);
22911963SAfshin.Ardakani@Sun.COM return;
23011963SAfshin.Ardakani@Sun.COM }
23111963SAfshin.Ardakani@Sun.COM
23211963SAfshin.Ardakani@Sun.COM (void) pthread_attr_init(&tattr);
23311963SAfshin.Ardakani@Sun.COM (void) pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED);
23411963SAfshin.Ardakani@Sun.COM rc = pthread_create(&thr, &tattr, dfs_namespace_cache, rootshr);
23511963SAfshin.Ardakani@Sun.COM (void) pthread_attr_destroy(&tattr);
23611963SAfshin.Ardakani@Sun.COM
23711963SAfshin.Ardakani@Sun.COM if (rc != 0)
23811963SAfshin.Ardakani@Sun.COM syslog(LOG_ERR, "dfs: fail to loading %s namespace (%d)",
23911963SAfshin.Ardakani@Sun.COM name, rc);
24011963SAfshin.Ardakani@Sun.COM }
24111963SAfshin.Ardakani@Sun.COM
24211963SAfshin.Ardakani@Sun.COM /*
24311963SAfshin.Ardakani@Sun.COM * Flushes the cache when a DFS root share is removed
24411963SAfshin.Ardakani@Sun.COM */
24511963SAfshin.Ardakani@Sun.COM void /*ARGSUSED*/
dfs_namespace_unload(const char * name)24611963SAfshin.Ardakani@Sun.COM dfs_namespace_unload(const char *name)
24711963SAfshin.Ardakani@Sun.COM {
248*12890SJoyce.McIntosh@Sun.COM dfs_cache_flush(name);
24911963SAfshin.Ardakani@Sun.COM }
25011963SAfshin.Ardakani@Sun.COM
25111963SAfshin.Ardakani@Sun.COM /*
25211963SAfshin.Ardakani@Sun.COM * Returns the file system path for the given share if it
25311963SAfshin.Ardakani@Sun.COM * is a DFS root share.
25411963SAfshin.Ardakani@Sun.COM * If 'path' is NULL, this function only indicates whether
25511963SAfshin.Ardakani@Sun.COM * or not the given share represents a DFS namespace
25611963SAfshin.Ardakani@Sun.COM */
25711963SAfshin.Ardakani@Sun.COM uint32_t
dfs_namespace_path(const char * name,char * path,size_t pathsz)25811963SAfshin.Ardakani@Sun.COM dfs_namespace_path(const char *name, char *path, size_t pathsz)
25911963SAfshin.Ardakani@Sun.COM {
26011963SAfshin.Ardakani@Sun.COM smb_share_t si;
26111963SAfshin.Ardakani@Sun.COM
26211963SAfshin.Ardakani@Sun.COM if (smb_shr_get((char *)name, &si) != NERR_Success)
26311963SAfshin.Ardakani@Sun.COM return (ERROR_NOT_FOUND);
26411963SAfshin.Ardakani@Sun.COM
26511963SAfshin.Ardakani@Sun.COM if ((si.shr_flags & SMB_SHRF_DFSROOT) == 0)
26611963SAfshin.Ardakani@Sun.COM return (ERROR_NOT_FOUND);
26711963SAfshin.Ardakani@Sun.COM
268*12890SJoyce.McIntosh@Sun.COM if (!dfs_namespace_iscached(name))
269*12890SJoyce.McIntosh@Sun.COM return (ERROR_NOT_FOUND);
270*12890SJoyce.McIntosh@Sun.COM
27111963SAfshin.Ardakani@Sun.COM if (path != NULL)
27211963SAfshin.Ardakani@Sun.COM (void) strlcpy(path, si.shr_path, pathsz);
27311963SAfshin.Ardakani@Sun.COM
27411963SAfshin.Ardakani@Sun.COM return (ERROR_SUCCESS);
27511963SAfshin.Ardakani@Sun.COM }
27611963SAfshin.Ardakani@Sun.COM
27711963SAfshin.Ardakani@Sun.COM /*
27811963SAfshin.Ardakani@Sun.COM * Returns the number of DFS root shares i.e. the number
27911963SAfshin.Ardakani@Sun.COM * of standalone namespaces.
28011963SAfshin.Ardakani@Sun.COM */
28111963SAfshin.Ardakani@Sun.COM uint32_t
dfs_namespace_count(void)28211963SAfshin.Ardakani@Sun.COM dfs_namespace_count(void)
28311963SAfshin.Ardakani@Sun.COM {
28411963SAfshin.Ardakani@Sun.COM uint32_t nroot = 0;
28512508Samw@Sun.COM int rc;
28612508Samw@Sun.COM
28712508Samw@Sun.COM if (dfs_intr_ops.dfsops_remote_count != NULL &&
28812508Samw@Sun.COM (rc = dfs_intr_ops.dfsops_remote_count(&nroot)) != 0) {
28912508Samw@Sun.COM /*
29012508Samw@Sun.COM * If this call fails, let's assume there's at least one root
29112508Samw@Sun.COM * namespace already configured. The interposer library cannot
29212508Samw@Sun.COM * confirm or deny the presence of a namespace, so let's take
29312508Samw@Sun.COM * the safe approach and assume one exists.
29412508Samw@Sun.COM */
29512508Samw@Sun.COM nroot = 1;
29612508Samw@Sun.COM syslog(LOG_WARNING, "dfs: dfsops_remote_count() failed: %d, "
29712508Samw@Sun.COM "assuming one namespace exists", rc);
29812508Samw@Sun.COM }
29911963SAfshin.Ardakani@Sun.COM
300*12890SJoyce.McIntosh@Sun.COM nroot += dfs_cache_nscount();
30111963SAfshin.Ardakani@Sun.COM
30211963SAfshin.Ardakani@Sun.COM return (nroot);
30311963SAfshin.Ardakani@Sun.COM }
30411963SAfshin.Ardakani@Sun.COM
30511963SAfshin.Ardakani@Sun.COM /*
30611963SAfshin.Ardakani@Sun.COM * Creates a DFS root with the given name and comment.
30711963SAfshin.Ardakani@Sun.COM *
30811963SAfshin.Ardakani@Sun.COM * This function does not create the root share, it
30911963SAfshin.Ardakani@Sun.COM * should already exist.
31011963SAfshin.Ardakani@Sun.COM */
31111963SAfshin.Ardakani@Sun.COM uint32_t
dfs_namespace_add(const char * rootshr,const char * cmnt)31211963SAfshin.Ardakani@Sun.COM dfs_namespace_add(const char *rootshr, const char *cmnt)
31311963SAfshin.Ardakani@Sun.COM {
31411963SAfshin.Ardakani@Sun.COM dfs_info_t info;
31511963SAfshin.Ardakani@Sun.COM dfs_target_t t;
31611963SAfshin.Ardakani@Sun.COM smb_share_t si;
31711963SAfshin.Ardakani@Sun.COM uuid_t uuid;
31811963SAfshin.Ardakani@Sun.COM uint32_t status;
31911963SAfshin.Ardakani@Sun.COM
32011963SAfshin.Ardakani@Sun.COM if (*rootshr == '\\') {
32111963SAfshin.Ardakani@Sun.COM /* Windows has a special case here! */
32211963SAfshin.Ardakani@Sun.COM return (ERROR_BAD_PATHNAME);
32311963SAfshin.Ardakani@Sun.COM }
32411963SAfshin.Ardakani@Sun.COM
32511963SAfshin.Ardakani@Sun.COM if (smb_shr_get((char *)rootshr, &si) != NERR_Success)
32611963SAfshin.Ardakani@Sun.COM return (NERR_NetNameNotFound);
32711963SAfshin.Ardakani@Sun.COM
328*12890SJoyce.McIntosh@Sun.COM (void) mutex_lock(&dfs_nsmtx);
329*12890SJoyce.McIntosh@Sun.COM if (smb_strcasecmp(dfs_cached_ns, rootshr, 0) == 0) {
330*12890SJoyce.McIntosh@Sun.COM /* This DFS root is already exported */
331*12890SJoyce.McIntosh@Sun.COM (void) mutex_unlock(&dfs_nsmtx);
33211963SAfshin.Ardakani@Sun.COM return (ERROR_FILE_EXISTS);
33311963SAfshin.Ardakani@Sun.COM }
33411963SAfshin.Ardakani@Sun.COM
335*12890SJoyce.McIntosh@Sun.COM if (*dfs_cached_ns != '\0') {
336*12890SJoyce.McIntosh@Sun.COM syslog(LOG_WARNING, "dfs: trying to add %s namespace."
337*12890SJoyce.McIntosh@Sun.COM " Only one standalone namespace is supported."
338*12890SJoyce.McIntosh@Sun.COM " A namespace is already exported for %s",
339*12890SJoyce.McIntosh@Sun.COM rootshr, dfs_cached_ns);
340*12890SJoyce.McIntosh@Sun.COM (void) mutex_unlock(&dfs_nsmtx);
341*12890SJoyce.McIntosh@Sun.COM return (ERROR_NOT_SUPPORTED);
342*12890SJoyce.McIntosh@Sun.COM }
343*12890SJoyce.McIntosh@Sun.COM
34411963SAfshin.Ardakani@Sun.COM bzero(&info, sizeof (info));
34511963SAfshin.Ardakani@Sun.COM if (cmnt)
34611963SAfshin.Ardakani@Sun.COM (void) strlcpy(info.i_comment, cmnt, sizeof (info.i_comment));
34711963SAfshin.Ardakani@Sun.COM info.i_state = DFS_VOLUME_STATE_OK | DFS_VOLUME_FLAVOR_STANDALONE;
34811963SAfshin.Ardakani@Sun.COM info.i_timeout = DFS_ROOT_TIMEOUT;
34911963SAfshin.Ardakani@Sun.COM info.i_propflags = 0;
35011963SAfshin.Ardakani@Sun.COM
35111963SAfshin.Ardakani@Sun.COM uuid_generate_random(uuid);
35211963SAfshin.Ardakani@Sun.COM uuid_unparse(uuid, info.i_guid);
35311963SAfshin.Ardakani@Sun.COM
35411963SAfshin.Ardakani@Sun.COM dfs_target_init(&t, dfs_nbname, rootshr, DFS_STORAGE_STATE_ONLINE);
35511963SAfshin.Ardakani@Sun.COM
35611963SAfshin.Ardakani@Sun.COM info.i_ntargets = 1;
35711963SAfshin.Ardakani@Sun.COM info.i_targets = &t;
35811963SAfshin.Ardakani@Sun.COM
359*12890SJoyce.McIntosh@Sun.COM if ((status = dfs_root_add(si.shr_path, &info)) != ERROR_SUCCESS) {
360*12890SJoyce.McIntosh@Sun.COM (void) mutex_unlock(&dfs_nsmtx);
36111963SAfshin.Ardakani@Sun.COM return (status);
362*12890SJoyce.McIntosh@Sun.COM }
36311963SAfshin.Ardakani@Sun.COM
36411963SAfshin.Ardakani@Sun.COM status = srvsvc_shr_setdfsroot(&si, B_TRUE);
365*12890SJoyce.McIntosh@Sun.COM if (status == ERROR_SUCCESS) {
36611963SAfshin.Ardakani@Sun.COM (void) dfs_cache_add_byname(rootshr, NULL, DFS_OBJECT_ROOT);
367*12890SJoyce.McIntosh@Sun.COM (void) strlcpy(dfs_cached_ns, rootshr, sizeof (dfs_cached_ns));
368*12890SJoyce.McIntosh@Sun.COM (void) smb_config_setnum(SMB_CI_DFS_STDROOT_NUM, 1);
369*12890SJoyce.McIntosh@Sun.COM }
370*12890SJoyce.McIntosh@Sun.COM (void) mutex_unlock(&dfs_nsmtx);
37111963SAfshin.Ardakani@Sun.COM
37211963SAfshin.Ardakani@Sun.COM return (status);
37311963SAfshin.Ardakani@Sun.COM }
37411963SAfshin.Ardakani@Sun.COM
37511963SAfshin.Ardakani@Sun.COM /*
37611963SAfshin.Ardakani@Sun.COM * Removes the namespace and all the links in it.
37711963SAfshin.Ardakani@Sun.COM */
37811963SAfshin.Ardakani@Sun.COM uint32_t
dfs_namespace_remove(const char * name)37911963SAfshin.Ardakani@Sun.COM dfs_namespace_remove(const char *name)
38011963SAfshin.Ardakani@Sun.COM {
38111963SAfshin.Ardakani@Sun.COM smb_cache_cursor_t cursor;
38211963SAfshin.Ardakani@Sun.COM dfs_nscnode_t nscnode;
38311963SAfshin.Ardakani@Sun.COM smb_share_t si;
38411963SAfshin.Ardakani@Sun.COM uint32_t status;
38511963SAfshin.Ardakani@Sun.COM
38611963SAfshin.Ardakani@Sun.COM if (smb_shr_get((char *)name, &si) != NERR_Success)
38711963SAfshin.Ardakani@Sun.COM return (ERROR_NOT_FOUND);
38811963SAfshin.Ardakani@Sun.COM
38911963SAfshin.Ardakani@Sun.COM if ((si.shr_flags & SMB_SHRF_DFSROOT) == 0)
39011963SAfshin.Ardakani@Sun.COM return (ERROR_NOT_FOUND);
39111963SAfshin.Ardakani@Sun.COM
39211963SAfshin.Ardakani@Sun.COM if ((status = dfs_root_remove(si.shr_path)) != ERROR_SUCCESS)
39311963SAfshin.Ardakani@Sun.COM return (status);
39411963SAfshin.Ardakani@Sun.COM
39511963SAfshin.Ardakani@Sun.COM status = srvsvc_shr_setdfsroot(&si, B_FALSE);
39611963SAfshin.Ardakani@Sun.COM if (status != ERROR_SUCCESS)
39711963SAfshin.Ardakani@Sun.COM syslog(LOG_WARNING, "dfs: failed to disable root share %s (%d)",
39811963SAfshin.Ardakani@Sun.COM name, status);
39911963SAfshin.Ardakani@Sun.COM
400*12890SJoyce.McIntosh@Sun.COM if (!dfs_namespace_iscached(name))
401*12890SJoyce.McIntosh@Sun.COM return (ERROR_SUCCESS);
402*12890SJoyce.McIntosh@Sun.COM
40311963SAfshin.Ardakani@Sun.COM smb_cache_iterinit(&dfs_nscache, &cursor);
40411963SAfshin.Ardakani@Sun.COM
40511963SAfshin.Ardakani@Sun.COM while (smb_cache_iterate(&dfs_nscache, &cursor, &nscnode)) {
40611963SAfshin.Ardakani@Sun.COM if (nscnode.nsc_type == DFS_OBJECT_ROOT)
40711963SAfshin.Ardakani@Sun.COM continue;
40811963SAfshin.Ardakani@Sun.COM status = dfs_link_remove(nscnode.nsc_fspath, NULL, NULL);
40911963SAfshin.Ardakani@Sun.COM if (status != ERROR_SUCCESS)
41011963SAfshin.Ardakani@Sun.COM syslog(LOG_WARNING, "dfs: failed to remove %s (%d)",
41111963SAfshin.Ardakani@Sun.COM nscnode.nsc_fspath, status);
41211963SAfshin.Ardakani@Sun.COM }
41311963SAfshin.Ardakani@Sun.COM
414*12890SJoyce.McIntosh@Sun.COM dfs_cache_flush(name);
41511963SAfshin.Ardakani@Sun.COM
41611963SAfshin.Ardakani@Sun.COM /* TODO: remove empty dirs */
41711963SAfshin.Ardakani@Sun.COM return (ERROR_SUCCESS);
41811963SAfshin.Ardakani@Sun.COM }
41911963SAfshin.Ardakani@Sun.COM
42011963SAfshin.Ardakani@Sun.COM /*
421*12890SJoyce.McIntosh@Sun.COM * Determines the DFS namespace flavor.
422*12890SJoyce.McIntosh@Sun.COM */
423*12890SJoyce.McIntosh@Sun.COM uint32_t
dfs_namespace_getflavor(const char * name)424*12890SJoyce.McIntosh@Sun.COM dfs_namespace_getflavor(const char *name)
425*12890SJoyce.McIntosh@Sun.COM {
426*12890SJoyce.McIntosh@Sun.COM char rootdir[DFS_PATH_MAX];
427*12890SJoyce.McIntosh@Sun.COM dfs_info_t info;
428*12890SJoyce.McIntosh@Sun.COM
429*12890SJoyce.McIntosh@Sun.COM if (dfs_namespace_path(name, rootdir, DFS_PATH_MAX) != ERROR_SUCCESS)
430*12890SJoyce.McIntosh@Sun.COM return (0);
431*12890SJoyce.McIntosh@Sun.COM
432*12890SJoyce.McIntosh@Sun.COM /* get flavor info from state info (info level 2) */
433*12890SJoyce.McIntosh@Sun.COM if (dfs_root_getinfo(rootdir, &info, 2) != ERROR_SUCCESS)
434*12890SJoyce.McIntosh@Sun.COM return (0);
435*12890SJoyce.McIntosh@Sun.COM
436*12890SJoyce.McIntosh@Sun.COM return (info.i_state & DFS_VOLUME_FLAVORS);
437*12890SJoyce.McIntosh@Sun.COM }
438*12890SJoyce.McIntosh@Sun.COM
439*12890SJoyce.McIntosh@Sun.COM /*
44011963SAfshin.Ardakani@Sun.COM * ==================
44111963SAfshin.Ardakani@Sun.COM * Root API (public)
44211963SAfshin.Ardakani@Sun.COM * ==================
44311963SAfshin.Ardakani@Sun.COM */
44411963SAfshin.Ardakani@Sun.COM
44511963SAfshin.Ardakani@Sun.COM /*
44611963SAfshin.Ardakani@Sun.COM * Retrieves the information of the root specified by its path.
44711963SAfshin.Ardakani@Sun.COM *
44811963SAfshin.Ardakani@Sun.COM * Info level (1) only needs the UNC path which is not stored,
44911963SAfshin.Ardakani@Sun.COM * it is constructed so the function will return without
45011963SAfshin.Ardakani@Sun.COM * accessing the backend storage.
45111963SAfshin.Ardakani@Sun.COM */
45211963SAfshin.Ardakani@Sun.COM uint32_t
dfs_root_getinfo(const char * rootdir,dfs_info_t * info,uint32_t infolvl)45311963SAfshin.Ardakani@Sun.COM dfs_root_getinfo(const char *rootdir, dfs_info_t *info, uint32_t infolvl)
45411963SAfshin.Ardakani@Sun.COM {
45511963SAfshin.Ardakani@Sun.COM uint32_t status = ERROR_INTERNAL_ERROR;
45611963SAfshin.Ardakani@Sun.COM int xfd;
45711963SAfshin.Ardakani@Sun.COM
45811963SAfshin.Ardakani@Sun.COM bzero(info, sizeof (dfs_info_t));
45911963SAfshin.Ardakani@Sun.COM info->i_type = DFS_OBJECT_ROOT;
46011963SAfshin.Ardakani@Sun.COM
46111963SAfshin.Ardakani@Sun.COM if (infolvl == 1)
46211963SAfshin.Ardakani@Sun.COM return (ERROR_SUCCESS);
46311963SAfshin.Ardakani@Sun.COM
46411963SAfshin.Ardakani@Sun.COM (void) rw_rdlock(&dfs_root_rwl);
46511963SAfshin.Ardakani@Sun.COM if ((xfd = dfs_root_xopen(rootdir, O_RDONLY)) > 0) {
46611963SAfshin.Ardakani@Sun.COM status = dfs_root_xread(xfd, info, infolvl);
46711963SAfshin.Ardakani@Sun.COM dfs_root_xclose(xfd);
46811963SAfshin.Ardakani@Sun.COM }
46911963SAfshin.Ardakani@Sun.COM (void) rw_unlock(&dfs_root_rwl);
47011963SAfshin.Ardakani@Sun.COM
47111963SAfshin.Ardakani@Sun.COM return (status);
47211963SAfshin.Ardakani@Sun.COM }
47311963SAfshin.Ardakani@Sun.COM
47411963SAfshin.Ardakani@Sun.COM /*
47511963SAfshin.Ardakani@Sun.COM * Sets the provided information for the specified root or root target.
47611963SAfshin.Ardakani@Sun.COM * Root is specified by 'rootdir' and the target is specified by
47711963SAfshin.Ardakani@Sun.COM * (t_server, t_share) pair. Only information items needed for given
47811963SAfshin.Ardakani@Sun.COM * information level (infolvl) is valid in the passed DFS info structure
47911963SAfshin.Ardakani@Sun.COM * 'info'.
48011963SAfshin.Ardakani@Sun.COM */
48111963SAfshin.Ardakani@Sun.COM uint32_t
dfs_root_setinfo(const char * rootdir,dfs_info_t * info,uint32_t infolvl)48211963SAfshin.Ardakani@Sun.COM dfs_root_setinfo(const char *rootdir, dfs_info_t *info, uint32_t infolvl)
48311963SAfshin.Ardakani@Sun.COM {
48411963SAfshin.Ardakani@Sun.COM dfs_info_t curinfo;
48511963SAfshin.Ardakani@Sun.COM uint32_t status = ERROR_SUCCESS;
48611963SAfshin.Ardakani@Sun.COM int xfd;
48711963SAfshin.Ardakani@Sun.COM
48811963SAfshin.Ardakani@Sun.COM (void) rw_wrlock(&dfs_root_rwl);
48911963SAfshin.Ardakani@Sun.COM if ((xfd = dfs_root_xopen(rootdir, O_RDWR)) < 0) {
49011963SAfshin.Ardakani@Sun.COM (void) rw_unlock(&dfs_root_rwl);
49111963SAfshin.Ardakani@Sun.COM return (ERROR_INTERNAL_ERROR);
49211963SAfshin.Ardakani@Sun.COM }
49311963SAfshin.Ardakani@Sun.COM
49411963SAfshin.Ardakani@Sun.COM status = dfs_root_xread(xfd, &curinfo, DFS_INFO_ALL);
49511963SAfshin.Ardakani@Sun.COM if (status != ERROR_SUCCESS) {
49611963SAfshin.Ardakani@Sun.COM dfs_root_xclose(xfd);
49711963SAfshin.Ardakani@Sun.COM (void) rw_unlock(&dfs_root_rwl);
49811963SAfshin.Ardakani@Sun.COM return (status);
49911963SAfshin.Ardakani@Sun.COM }
50011963SAfshin.Ardakani@Sun.COM
50111963SAfshin.Ardakani@Sun.COM status = dfs_modinfo(DFS_OBJECT_ROOT, &curinfo, info, infolvl);
50211963SAfshin.Ardakani@Sun.COM if (status == ERROR_SUCCESS)
50311963SAfshin.Ardakani@Sun.COM status = dfs_root_xwrite(xfd, &curinfo);
50411963SAfshin.Ardakani@Sun.COM
50511963SAfshin.Ardakani@Sun.COM dfs_root_xclose(xfd);
50611963SAfshin.Ardakani@Sun.COM (void) rw_unlock(&dfs_root_rwl);
50711963SAfshin.Ardakani@Sun.COM
50811963SAfshin.Ardakani@Sun.COM dfs_info_free(&curinfo);
50911963SAfshin.Ardakani@Sun.COM return (status);
51011963SAfshin.Ardakani@Sun.COM }
51111963SAfshin.Ardakani@Sun.COM
51211963SAfshin.Ardakani@Sun.COM /*
51311963SAfshin.Ardakani@Sun.COM * ==================
51411963SAfshin.Ardakani@Sun.COM * Link API (public)
51511963SAfshin.Ardakani@Sun.COM * ==================
51611963SAfshin.Ardakani@Sun.COM */
51711963SAfshin.Ardakani@Sun.COM
51811963SAfshin.Ardakani@Sun.COM /*
51911963SAfshin.Ardakani@Sun.COM * Gets the status of the given path as a link
52011963SAfshin.Ardakani@Sun.COM */
52111963SAfshin.Ardakani@Sun.COM uint32_t
dfs_link_stat(const char * path,uint32_t * stat)52211963SAfshin.Ardakani@Sun.COM dfs_link_stat(const char *path, uint32_t *stat)
52311963SAfshin.Ardakani@Sun.COM {
52411963SAfshin.Ardakani@Sun.COM if (smb_reparse_stat(path, stat) != 0)
52511963SAfshin.Ardakani@Sun.COM return (ERROR_INTERNAL_ERROR);
52611963SAfshin.Ardakani@Sun.COM
52711963SAfshin.Ardakani@Sun.COM switch (*stat) {
52811963SAfshin.Ardakani@Sun.COM case SMB_REPARSE_NOTFOUND:
52911963SAfshin.Ardakani@Sun.COM *stat = DFS_STAT_NOTFOUND;
53011963SAfshin.Ardakani@Sun.COM break;
53111963SAfshin.Ardakani@Sun.COM case SMB_REPARSE_NOTREPARSE:
53211963SAfshin.Ardakani@Sun.COM *stat = DFS_STAT_NOTLINK;
53311963SAfshin.Ardakani@Sun.COM break;
53411963SAfshin.Ardakani@Sun.COM case SMB_REPARSE_ISREPARSE:
53511963SAfshin.Ardakani@Sun.COM *stat = DFS_STAT_ISREPARSE;
53611963SAfshin.Ardakani@Sun.COM if (smb_reparse_svcget(path, DFS_REPARSE_SVCTYPE, NULL) == 0)
53711963SAfshin.Ardakani@Sun.COM *stat = DFS_STAT_ISDFS;
53811963SAfshin.Ardakani@Sun.COM break;
53911963SAfshin.Ardakani@Sun.COM default:
54011963SAfshin.Ardakani@Sun.COM *stat = DFS_STAT_UNKNOWN;
54111963SAfshin.Ardakani@Sun.COM break;
54211963SAfshin.Ardakani@Sun.COM }
54311963SAfshin.Ardakani@Sun.COM
54411963SAfshin.Ardakani@Sun.COM return (ERROR_SUCCESS);
54511963SAfshin.Ardakani@Sun.COM }
54611963SAfshin.Ardakani@Sun.COM
54711963SAfshin.Ardakani@Sun.COM /*
54811963SAfshin.Ardakani@Sun.COM * Creates a new DFS link or adds a new target to an existing link
54911963SAfshin.Ardakani@Sun.COM */
55011963SAfshin.Ardakani@Sun.COM uint32_t
dfs_link_add(const char * path,const char * server,const char * share,const char * cmnt,uint32_t flags,boolean_t * newlink)55111963SAfshin.Ardakani@Sun.COM dfs_link_add(const char *path, const char *server, const char *share,
55211963SAfshin.Ardakani@Sun.COM const char *cmnt, uint32_t flags, boolean_t *newlink)
55311963SAfshin.Ardakani@Sun.COM {
55411963SAfshin.Ardakani@Sun.COM dfs_info_t info;
55511963SAfshin.Ardakani@Sun.COM dfs_target_t *t;
55611963SAfshin.Ardakani@Sun.COM int ntargets;
55711963SAfshin.Ardakani@Sun.COM uint32_t status;
55811963SAfshin.Ardakani@Sun.COM uint32_t stat;
55911963SAfshin.Ardakani@Sun.COM
56011963SAfshin.Ardakani@Sun.COM *newlink = B_FALSE;
56111963SAfshin.Ardakani@Sun.COM
56211963SAfshin.Ardakani@Sun.COM if ((status = dfs_link_stat(path, &stat)) != ERROR_SUCCESS)
56311963SAfshin.Ardakani@Sun.COM return (status);
56411963SAfshin.Ardakani@Sun.COM
56511963SAfshin.Ardakani@Sun.COM switch (stat) {
56611963SAfshin.Ardakani@Sun.COM case DFS_STAT_NOTFOUND:
56711963SAfshin.Ardakani@Sun.COM case DFS_STAT_ISREPARSE:
56811963SAfshin.Ardakani@Sun.COM /* Create a new DFS link */
56911963SAfshin.Ardakani@Sun.COM
57011963SAfshin.Ardakani@Sun.COM status = dfs_link_getinfo(NULL, &info, DFS_INFO_ALL);
57111963SAfshin.Ardakani@Sun.COM if (status != ERROR_SUCCESS)
57211963SAfshin.Ardakani@Sun.COM return (status);
57311963SAfshin.Ardakani@Sun.COM
57411963SAfshin.Ardakani@Sun.COM (void) strlcpy(info.i_comment, (cmnt) ? cmnt : "",
57511963SAfshin.Ardakani@Sun.COM sizeof (info.i_comment));
57611963SAfshin.Ardakani@Sun.COM *newlink = B_TRUE;
57711963SAfshin.Ardakani@Sun.COM break;
57811963SAfshin.Ardakani@Sun.COM
57911963SAfshin.Ardakani@Sun.COM case DFS_STAT_ISDFS:
58011963SAfshin.Ardakani@Sun.COM /* Add a target to an existing link */
58111963SAfshin.Ardakani@Sun.COM
58211963SAfshin.Ardakani@Sun.COM if (flags & DFS_ADD_VOLUME)
58311963SAfshin.Ardakani@Sun.COM return (ERROR_FILE_EXISTS);
58411963SAfshin.Ardakani@Sun.COM
58511963SAfshin.Ardakani@Sun.COM status = dfs_link_getinfo(path, &info, DFS_INFO_ALL);
58611963SAfshin.Ardakani@Sun.COM if (status != ERROR_SUCCESS)
58711963SAfshin.Ardakani@Sun.COM return (status);
58811963SAfshin.Ardakani@Sun.COM
58911963SAfshin.Ardakani@Sun.COM break;
59011963SAfshin.Ardakani@Sun.COM
59111963SAfshin.Ardakani@Sun.COM case DFS_STAT_NOTLINK:
59211963SAfshin.Ardakani@Sun.COM /* specified path points to a non-reparse object */
59311963SAfshin.Ardakani@Sun.COM return (ERROR_FILE_EXISTS);
59411963SAfshin.Ardakani@Sun.COM
59511963SAfshin.Ardakani@Sun.COM default:
59611963SAfshin.Ardakani@Sun.COM return (ERROR_INTERNAL_ERROR);
59711963SAfshin.Ardakani@Sun.COM }
59811963SAfshin.Ardakani@Sun.COM
59911963SAfshin.Ardakani@Sun.COM /* checks to see if the target already exists */
60011963SAfshin.Ardakani@Sun.COM ntargets = info.i_ntargets;
60111963SAfshin.Ardakani@Sun.COM if (dfs_target_find(info.i_targets, ntargets, server, share) != -1) {
60211963SAfshin.Ardakani@Sun.COM dfs_info_free(&info);
60311963SAfshin.Ardakani@Sun.COM return (ERROR_FILE_EXISTS);
60411963SAfshin.Ardakani@Sun.COM }
60511963SAfshin.Ardakani@Sun.COM
60611963SAfshin.Ardakani@Sun.COM /* add the new target */
60711963SAfshin.Ardakani@Sun.COM t = realloc(info.i_targets, (ntargets + 1) * sizeof (dfs_target_t));
60811963SAfshin.Ardakani@Sun.COM if (t == NULL) {
60911963SAfshin.Ardakani@Sun.COM dfs_info_free(&info);
61011963SAfshin.Ardakani@Sun.COM return (ERROR_NOT_ENOUGH_MEMORY);
61111963SAfshin.Ardakani@Sun.COM }
61211963SAfshin.Ardakani@Sun.COM
61311963SAfshin.Ardakani@Sun.COM info.i_targets = t;
61411963SAfshin.Ardakani@Sun.COM dfs_target_init(&info.i_targets[ntargets], server, share,
61511963SAfshin.Ardakani@Sun.COM DFS_STORAGE_STATE_ONLINE);
61611963SAfshin.Ardakani@Sun.COM info.i_ntargets++;
61711963SAfshin.Ardakani@Sun.COM
61811963SAfshin.Ardakani@Sun.COM status = dfs_link_commit(path, &info);
61911963SAfshin.Ardakani@Sun.COM
62011963SAfshin.Ardakani@Sun.COM dfs_info_free(&info);
62111963SAfshin.Ardakani@Sun.COM return (status);
62211963SAfshin.Ardakani@Sun.COM }
62311963SAfshin.Ardakani@Sun.COM
62411963SAfshin.Ardakani@Sun.COM /*
62511963SAfshin.Ardakani@Sun.COM * Removes a link or a link target from a DFS namespace. A link can be
62611963SAfshin.Ardakani@Sun.COM * removed regardless of the number of targets associated with it.
62711963SAfshin.Ardakani@Sun.COM *
62811963SAfshin.Ardakani@Sun.COM * 'server' and 'share' parameters specify a target, so if they are NULL
62911963SAfshin.Ardakani@Sun.COM * it means the link should be removed, otherwise the specified target
63011963SAfshin.Ardakani@Sun.COM * is removed if found.
63111963SAfshin.Ardakani@Sun.COM */
63211963SAfshin.Ardakani@Sun.COM uint32_t
dfs_link_remove(const char * path,const char * server,const char * share)63311963SAfshin.Ardakani@Sun.COM dfs_link_remove(const char *path, const char *server, const char *share)
63411963SAfshin.Ardakani@Sun.COM {
63511963SAfshin.Ardakani@Sun.COM dfs_info_t info;
63611963SAfshin.Ardakani@Sun.COM uint32_t status, stat;
63711963SAfshin.Ardakani@Sun.COM int rc, idx;
63811963SAfshin.Ardakani@Sun.COM
63911963SAfshin.Ardakani@Sun.COM if ((status = dfs_link_stat(path, &stat)) != ERROR_SUCCESS)
64011963SAfshin.Ardakani@Sun.COM return (status);
64111963SAfshin.Ardakani@Sun.COM
64211963SAfshin.Ardakani@Sun.COM if (stat != DFS_STAT_ISDFS)
64311963SAfshin.Ardakani@Sun.COM return (ERROR_NOT_FOUND);
64411963SAfshin.Ardakani@Sun.COM
64511963SAfshin.Ardakani@Sun.COM if (server == NULL && share == NULL) {
64611963SAfshin.Ardakani@Sun.COM /* remove the link */
64711963SAfshin.Ardakani@Sun.COM if (smb_reparse_svcdel(path, DFS_REPARSE_SVCTYPE) != 0)
64811963SAfshin.Ardakani@Sun.COM return (ERROR_INTERNAL_ERROR);
64911963SAfshin.Ardakani@Sun.COM
65011963SAfshin.Ardakani@Sun.COM return (ERROR_SUCCESS);
65111963SAfshin.Ardakani@Sun.COM }
65211963SAfshin.Ardakani@Sun.COM
65311963SAfshin.Ardakani@Sun.COM /* remove the specified target in the link */
65411963SAfshin.Ardakani@Sun.COM
65511963SAfshin.Ardakani@Sun.COM status = dfs_link_getinfo(path, &info, DFS_INFO_ALL);
65611963SAfshin.Ardakani@Sun.COM if (status != ERROR_SUCCESS)
65711963SAfshin.Ardakani@Sun.COM return (status);
65811963SAfshin.Ardakani@Sun.COM
65911963SAfshin.Ardakani@Sun.COM /* checks to see if the target exists */
66011963SAfshin.Ardakani@Sun.COM idx = dfs_target_find(info.i_targets, info.i_ntargets, server, share);
66111963SAfshin.Ardakani@Sun.COM if (idx != -1) {
66211963SAfshin.Ardakani@Sun.COM bcopy(&info.i_targets[idx + 1], &info.i_targets[idx],
66311963SAfshin.Ardakani@Sun.COM (info.i_ntargets - idx - 1) * sizeof (dfs_target_t));
66411963SAfshin.Ardakani@Sun.COM info.i_ntargets--;
66511963SAfshin.Ardakani@Sun.COM } else {
66611963SAfshin.Ardakani@Sun.COM dfs_info_free(&info);
66711963SAfshin.Ardakani@Sun.COM return (ERROR_FILE_NOT_FOUND);
66811963SAfshin.Ardakani@Sun.COM }
66911963SAfshin.Ardakani@Sun.COM
67011963SAfshin.Ardakani@Sun.COM if (info.i_ntargets == 0) {
67111963SAfshin.Ardakani@Sun.COM /* if last target, then remove the link */
67211963SAfshin.Ardakani@Sun.COM rc = smb_reparse_svcdel(path, DFS_REPARSE_SVCTYPE);
67311963SAfshin.Ardakani@Sun.COM status = (rc == 0) ? ERROR_SUCCESS : ERROR_INTERNAL_ERROR;
67411963SAfshin.Ardakani@Sun.COM } else {
67511963SAfshin.Ardakani@Sun.COM status = dfs_link_commit(path, &info);
67611963SAfshin.Ardakani@Sun.COM }
67711963SAfshin.Ardakani@Sun.COM
67811963SAfshin.Ardakani@Sun.COM dfs_info_free(&info);
67911963SAfshin.Ardakani@Sun.COM return (status);
68011963SAfshin.Ardakani@Sun.COM }
68111963SAfshin.Ardakani@Sun.COM
68211963SAfshin.Ardakani@Sun.COM /*
68311963SAfshin.Ardakani@Sun.COM * Sets the provided information for the specified link or link target.
68411963SAfshin.Ardakani@Sun.COM * Link is specified by 'path' and the target is specified by
68511963SAfshin.Ardakani@Sun.COM * (t_server, t_share) pair. Only information items needed for given
68611963SAfshin.Ardakani@Sun.COM * information level (infolvl) is valid in the passed DFS info structure
68711963SAfshin.Ardakani@Sun.COM * 'info'.
68811963SAfshin.Ardakani@Sun.COM */
68911963SAfshin.Ardakani@Sun.COM uint32_t
dfs_link_setinfo(const char * path,dfs_info_t * info,uint32_t infolvl)69011963SAfshin.Ardakani@Sun.COM dfs_link_setinfo(const char *path, dfs_info_t *info, uint32_t infolvl)
69111963SAfshin.Ardakani@Sun.COM {
69211963SAfshin.Ardakani@Sun.COM dfs_info_t curinfo;
69311963SAfshin.Ardakani@Sun.COM uint32_t status;
69411963SAfshin.Ardakani@Sun.COM
69511963SAfshin.Ardakani@Sun.COM status = dfs_link_getinfo(path, &curinfo, DFS_INFO_ALL);
69611963SAfshin.Ardakani@Sun.COM if (status != ERROR_SUCCESS)
69711963SAfshin.Ardakani@Sun.COM return (status);
69811963SAfshin.Ardakani@Sun.COM
69911963SAfshin.Ardakani@Sun.COM status = dfs_modinfo(DFS_OBJECT_LINK, &curinfo, info, infolvl);
70011963SAfshin.Ardakani@Sun.COM if (status == ERROR_SUCCESS)
70111963SAfshin.Ardakani@Sun.COM status = dfs_link_commit(path, &curinfo);
70211963SAfshin.Ardakani@Sun.COM
70311963SAfshin.Ardakani@Sun.COM dfs_info_free(&curinfo);
70411963SAfshin.Ardakani@Sun.COM return (status);
70511963SAfshin.Ardakani@Sun.COM }
70611963SAfshin.Ardakani@Sun.COM
70711963SAfshin.Ardakani@Sun.COM /*
70811963SAfshin.Ardakani@Sun.COM * Gets the DFS link info.
70911963SAfshin.Ardakani@Sun.COM *
71011963SAfshin.Ardakani@Sun.COM * If path is NULL, it just does some initialization.
71111963SAfshin.Ardakani@Sun.COM *
71211963SAfshin.Ardakani@Sun.COM * Info level (1) only needs the UNC path which is not
71311963SAfshin.Ardakani@Sun.COM * stored, it is constructed so the function will return
71411963SAfshin.Ardakani@Sun.COM * without accessing the backend storage.
71511963SAfshin.Ardakani@Sun.COM */
71611963SAfshin.Ardakani@Sun.COM uint32_t
dfs_link_getinfo(const char * path,dfs_info_t * info,uint32_t infolvl)71711963SAfshin.Ardakani@Sun.COM dfs_link_getinfo(const char *path, dfs_info_t *info, uint32_t infolvl)
71811963SAfshin.Ardakani@Sun.COM {
71911963SAfshin.Ardakani@Sun.COM char *link_data;
72011963SAfshin.Ardakani@Sun.COM uint32_t status;
72111963SAfshin.Ardakani@Sun.COM uuid_t uuid;
72211963SAfshin.Ardakani@Sun.COM int rc;
72311963SAfshin.Ardakani@Sun.COM
72411963SAfshin.Ardakani@Sun.COM bzero(info, sizeof (dfs_info_t));
72511963SAfshin.Ardakani@Sun.COM info->i_type = DFS_OBJECT_LINK;
72611963SAfshin.Ardakani@Sun.COM
72711963SAfshin.Ardakani@Sun.COM if (path == NULL) {
72811963SAfshin.Ardakani@Sun.COM info->i_state = DFS_VOLUME_STATE_OK;
72911963SAfshin.Ardakani@Sun.COM info->i_timeout = DFS_LINK_TIMEOUT;
73011963SAfshin.Ardakani@Sun.COM info->i_propflags = 0;
73111963SAfshin.Ardakani@Sun.COM uuid_generate_random(uuid);
73211963SAfshin.Ardakani@Sun.COM uuid_unparse(uuid, info->i_guid);
73311963SAfshin.Ardakani@Sun.COM return (ERROR_SUCCESS);
73411963SAfshin.Ardakani@Sun.COM }
73511963SAfshin.Ardakani@Sun.COM
73611963SAfshin.Ardakani@Sun.COM if (infolvl == 1)
73711963SAfshin.Ardakani@Sun.COM return (ERROR_SUCCESS);
73811963SAfshin.Ardakani@Sun.COM
73911963SAfshin.Ardakani@Sun.COM rc = smb_reparse_svcget(path, DFS_REPARSE_SVCTYPE, &link_data);
74011963SAfshin.Ardakani@Sun.COM if (rc != 0)
74111963SAfshin.Ardakani@Sun.COM return (ERROR_INTERNAL_ERROR);
74211963SAfshin.Ardakani@Sun.COM
74311963SAfshin.Ardakani@Sun.COM status = dfs_link_decode(info, link_data, infolvl);
74411963SAfshin.Ardakani@Sun.COM free(link_data);
74511963SAfshin.Ardakani@Sun.COM
74611963SAfshin.Ardakani@Sun.COM return (status);
74711963SAfshin.Ardakani@Sun.COM }
74811963SAfshin.Ardakani@Sun.COM
74911963SAfshin.Ardakani@Sun.COM /*
75011963SAfshin.Ardakani@Sun.COM * ===================
75111963SAfshin.Ardakani@Sun.COM * Cache API (public)
75211963SAfshin.Ardakani@Sun.COM * ===================
75311963SAfshin.Ardakani@Sun.COM */
75411963SAfshin.Ardakani@Sun.COM
75511963SAfshin.Ardakani@Sun.COM /*
75611963SAfshin.Ardakani@Sun.COM * Adds an entry with given DFS name (root sharename) and relative path
75711963SAfshin.Ardakani@Sun.COM * to the share (relpath) and the specified entry type (i.e. root/link)
75811963SAfshin.Ardakani@Sun.COM * to the namespace cache.
75911963SAfshin.Ardakani@Sun.COM */
76011963SAfshin.Ardakani@Sun.COM uint32_t
dfs_cache_add_byname(const char * name,const char * relpath,uint32_t type)76111963SAfshin.Ardakani@Sun.COM dfs_cache_add_byname(const char *name, const char *relpath, uint32_t type)
76211963SAfshin.Ardakani@Sun.COM {
76311963SAfshin.Ardakani@Sun.COM char uncpath[DFS_PATH_MAX];
76411963SAfshin.Ardakani@Sun.COM char fspath[DFS_PATH_MAX];
76511963SAfshin.Ardakani@Sun.COM smb_share_t si;
76611963SAfshin.Ardakani@Sun.COM
76711963SAfshin.Ardakani@Sun.COM if (smb_shr_get((char *)name, &si) != NERR_Success)
76811963SAfshin.Ardakani@Sun.COM return (ERROR_NOT_FOUND);
76911963SAfshin.Ardakani@Sun.COM
77011963SAfshin.Ardakani@Sun.COM if (type == DFS_OBJECT_ROOT) {
77111963SAfshin.Ardakani@Sun.COM (void) snprintf(uncpath, DFS_PATH_MAX, "\\\\%s\\%s",
77211963SAfshin.Ardakani@Sun.COM dfs_nbname, name);
77311963SAfshin.Ardakani@Sun.COM return (dfs_cache_add_byunc(uncpath, si.shr_path, type));
77411963SAfshin.Ardakani@Sun.COM }
77511963SAfshin.Ardakani@Sun.COM
77611963SAfshin.Ardakani@Sun.COM /* add link entry */
77711963SAfshin.Ardakani@Sun.COM (void) snprintf(fspath, DFS_PATH_MAX, "%s/%s", si.shr_path, relpath);
77811963SAfshin.Ardakani@Sun.COM (void) snprintf(uncpath, DFS_PATH_MAX, "\\\\%s\\%s\\%s", dfs_nbname,
77911963SAfshin.Ardakani@Sun.COM name, relpath);
78011963SAfshin.Ardakani@Sun.COM
78111963SAfshin.Ardakani@Sun.COM /* relpath may contain '/' */
78211963SAfshin.Ardakani@Sun.COM (void) strsubst(uncpath, '/', '\\');
78311963SAfshin.Ardakani@Sun.COM
78411963SAfshin.Ardakani@Sun.COM return (dfs_cache_add_byunc(uncpath, fspath, type));
78511963SAfshin.Ardakani@Sun.COM }
78611963SAfshin.Ardakani@Sun.COM
78711963SAfshin.Ardakani@Sun.COM /*
78811963SAfshin.Ardakani@Sun.COM * Removes the namespace cache entry for the given link
78911963SAfshin.Ardakani@Sun.COM * in the namespace ('name') with 'relpath'
79011963SAfshin.Ardakani@Sun.COM */
79111963SAfshin.Ardakani@Sun.COM void
dfs_cache_remove(const char * name,const char * relpath)79211963SAfshin.Ardakani@Sun.COM dfs_cache_remove(const char *name, const char *relpath)
79311963SAfshin.Ardakani@Sun.COM {
79411963SAfshin.Ardakani@Sun.COM dfs_nscnode_t dn;
79511963SAfshin.Ardakani@Sun.COM
79611963SAfshin.Ardakani@Sun.COM (void) snprintf(dn.nsc_uncpath, sizeof (dn.nsc_uncpath),
79711963SAfshin.Ardakani@Sun.COM "\\\\%s\\%s\\%s", dfs_nbname, name, relpath);
79811963SAfshin.Ardakani@Sun.COM
79911963SAfshin.Ardakani@Sun.COM /* relpath may contain '/' */
80011963SAfshin.Ardakani@Sun.COM (void) strsubst(dn.nsc_uncpath, '/', '\\');
80111963SAfshin.Ardakani@Sun.COM
80211963SAfshin.Ardakani@Sun.COM smb_cache_remove(&dfs_nscache, &dn);
80311963SAfshin.Ardakani@Sun.COM }
80411963SAfshin.Ardakani@Sun.COM
80511963SAfshin.Ardakani@Sun.COM /*
80611963SAfshin.Ardakani@Sun.COM * Get the DFS data for the specified cache entry
80711963SAfshin.Ardakani@Sun.COM */
80811963SAfshin.Ardakani@Sun.COM uint32_t
dfs_cache_getinfo(dfs_nscnode_t * dn,dfs_info_t * info,uint32_t infolvl)80911963SAfshin.Ardakani@Sun.COM dfs_cache_getinfo(dfs_nscnode_t *dn, dfs_info_t *info, uint32_t infolvl)
81011963SAfshin.Ardakani@Sun.COM {
81111963SAfshin.Ardakani@Sun.COM uint32_t status;
81211963SAfshin.Ardakani@Sun.COM
81311963SAfshin.Ardakani@Sun.COM if (dn->nsc_type == DFS_OBJECT_LINK)
81411963SAfshin.Ardakani@Sun.COM status = dfs_link_getinfo(dn->nsc_fspath, info, infolvl);
81511963SAfshin.Ardakani@Sun.COM else
81611963SAfshin.Ardakani@Sun.COM status = dfs_root_getinfo(dn->nsc_fspath, info, infolvl);
81711963SAfshin.Ardakani@Sun.COM
81811963SAfshin.Ardakani@Sun.COM (void) strlcpy(info->i_uncpath, dn->nsc_uncpath,
81911963SAfshin.Ardakani@Sun.COM sizeof (info->i_uncpath));
82011963SAfshin.Ardakani@Sun.COM
82111963SAfshin.Ardakani@Sun.COM if (status == ERROR_SUCCESS)
82211963SAfshin.Ardakani@Sun.COM dfs_info_trace("dfs_cache_getinfo", info);
82311963SAfshin.Ardakani@Sun.COM
82411963SAfshin.Ardakani@Sun.COM return (status);
82511963SAfshin.Ardakani@Sun.COM }
82611963SAfshin.Ardakani@Sun.COM
82711963SAfshin.Ardakani@Sun.COM /*
82811963SAfshin.Ardakani@Sun.COM * Returns the number of cache entries i.e. the number of
82911963SAfshin.Ardakani@Sun.COM * root(s) and link(s)
83011963SAfshin.Ardakani@Sun.COM */
83111963SAfshin.Ardakani@Sun.COM uint32_t
dfs_cache_num(void)83211963SAfshin.Ardakani@Sun.COM dfs_cache_num(void)
83311963SAfshin.Ardakani@Sun.COM {
83411963SAfshin.Ardakani@Sun.COM return (smb_cache_num(&dfs_nscache));
83511963SAfshin.Ardakani@Sun.COM }
83611963SAfshin.Ardakani@Sun.COM
83711963SAfshin.Ardakani@Sun.COM void
dfs_cache_iterinit(smb_cache_cursor_t * cursor)83811963SAfshin.Ardakani@Sun.COM dfs_cache_iterinit(smb_cache_cursor_t *cursor)
83911963SAfshin.Ardakani@Sun.COM {
84011963SAfshin.Ardakani@Sun.COM smb_cache_iterinit(&dfs_nscache, cursor);
84111963SAfshin.Ardakani@Sun.COM }
84211963SAfshin.Ardakani@Sun.COM
84311963SAfshin.Ardakani@Sun.COM boolean_t
dfs_cache_iterate(smb_cache_cursor_t * cursor,dfs_nscnode_t * dn)84411963SAfshin.Ardakani@Sun.COM dfs_cache_iterate(smb_cache_cursor_t *cursor, dfs_nscnode_t *dn)
84511963SAfshin.Ardakani@Sun.COM {
84611963SAfshin.Ardakani@Sun.COM return (smb_cache_iterate(&dfs_nscache, cursor, dn));
84711963SAfshin.Ardakani@Sun.COM }
84811963SAfshin.Ardakani@Sun.COM
84911963SAfshin.Ardakani@Sun.COM /*
85011963SAfshin.Ardakani@Sun.COM * ==================
85111963SAfshin.Ardakani@Sun.COM * Misc API (public)
85211963SAfshin.Ardakani@Sun.COM * ==================
85311963SAfshin.Ardakani@Sun.COM */
85411963SAfshin.Ardakani@Sun.COM
85511963SAfshin.Ardakani@Sun.COM /*
85611963SAfshin.Ardakani@Sun.COM * This is the function that is called by smbd door server to
85711963SAfshin.Ardakani@Sun.COM * fullfil a GetReferrals request from smbsrv kernel module
85811963SAfshin.Ardakani@Sun.COM *
85911963SAfshin.Ardakani@Sun.COM * 'reftype' specifies the requested referral type. If it is
86011963SAfshin.Ardakani@Sun.COM * DFS_REFERRAL_ROOT then dfs_path should point to a namespace
86111963SAfshin.Ardakani@Sun.COM * root. If it is DFS_REFERRAL_LINK then dfs_path should CONTAIN
86211963SAfshin.Ardakani@Sun.COM * a link, in which case this function will find the link and
86311963SAfshin.Ardakani@Sun.COM * returns its target information.
86411963SAfshin.Ardakani@Sun.COM */
86511963SAfshin.Ardakani@Sun.COM uint32_t
dfs_get_referrals(const char * dfs_path,dfs_reftype_t reftype,dfs_info_t * referrals)86611963SAfshin.Ardakani@Sun.COM dfs_get_referrals(const char *dfs_path, dfs_reftype_t reftype,
86711963SAfshin.Ardakani@Sun.COM dfs_info_t *referrals)
86811963SAfshin.Ardakani@Sun.COM {
86911963SAfshin.Ardakani@Sun.COM dfs_path_t path;
87011963SAfshin.Ardakani@Sun.COM smb_unc_t *unc;
87111963SAfshin.Ardakani@Sun.COM char linkpath[DFS_PATH_MAX];
87211963SAfshin.Ardakani@Sun.COM uint32_t status;
87311963SAfshin.Ardakani@Sun.COM
87411963SAfshin.Ardakani@Sun.COM status = dfs_path_parse(&path, dfs_path, DFS_OBJECT_ANY);
87511963SAfshin.Ardakani@Sun.COM if (status != ERROR_SUCCESS)
87611963SAfshin.Ardakani@Sun.COM return (status);
87711963SAfshin.Ardakani@Sun.COM
87811963SAfshin.Ardakani@Sun.COM dfs_setpriv(PRIV_ON);
87911963SAfshin.Ardakani@Sun.COM
88011963SAfshin.Ardakani@Sun.COM referrals->i_type = path.p_type;
88111963SAfshin.Ardakani@Sun.COM
88211963SAfshin.Ardakani@Sun.COM switch (reftype) {
88311963SAfshin.Ardakani@Sun.COM case DFS_REFERRAL_ROOT:
88411963SAfshin.Ardakani@Sun.COM if (path.p_type != DFS_OBJECT_ROOT) {
88511963SAfshin.Ardakani@Sun.COM status = ERROR_INVALID_PARAMETER;
88611963SAfshin.Ardakani@Sun.COM break;
88711963SAfshin.Ardakani@Sun.COM }
88811963SAfshin.Ardakani@Sun.COM
88911963SAfshin.Ardakani@Sun.COM status = dfs_root_getinfo((const char *)path.p_fspath,
89011963SAfshin.Ardakani@Sun.COM referrals, DFS_INFO_ALL);
89111963SAfshin.Ardakani@Sun.COM (void) strlcpy(referrals->i_uncpath, dfs_path, DFS_PATH_MAX);
89211963SAfshin.Ardakani@Sun.COM break;
89311963SAfshin.Ardakani@Sun.COM
89411963SAfshin.Ardakani@Sun.COM case DFS_REFERRAL_LINK:
89511963SAfshin.Ardakani@Sun.COM if (path.p_type != DFS_OBJECT_LINK) {
89611963SAfshin.Ardakani@Sun.COM status = ERROR_INVALID_PARAMETER;
89711963SAfshin.Ardakani@Sun.COM break;
89811963SAfshin.Ardakani@Sun.COM }
89911963SAfshin.Ardakani@Sun.COM
90011963SAfshin.Ardakani@Sun.COM unc = &path.p_unc;
90111963SAfshin.Ardakani@Sun.COM if (!dfs_namespace_findlink(unc->unc_share, unc->unc_path,
90211963SAfshin.Ardakani@Sun.COM linkpath, DFS_PATH_MAX)) {
90311963SAfshin.Ardakani@Sun.COM status = ERROR_NOT_FOUND;
90411963SAfshin.Ardakani@Sun.COM break;
90511963SAfshin.Ardakani@Sun.COM }
90611963SAfshin.Ardakani@Sun.COM
90711963SAfshin.Ardakani@Sun.COM status = dfs_link_getinfo(linkpath, referrals, DFS_INFO_ALL);
90811963SAfshin.Ardakani@Sun.COM (void) snprintf(referrals->i_uncpath, DFS_PATH_MAX, "/%s/%s/%s",
90911963SAfshin.Ardakani@Sun.COM unc->unc_server, unc->unc_share, unc->unc_path);
91011963SAfshin.Ardakani@Sun.COM break;
91111963SAfshin.Ardakani@Sun.COM
91211963SAfshin.Ardakani@Sun.COM default:
91311963SAfshin.Ardakani@Sun.COM status = ERROR_INVALID_PARAMETER;
91411963SAfshin.Ardakani@Sun.COM break;
91511963SAfshin.Ardakani@Sun.COM }
91611963SAfshin.Ardakani@Sun.COM
91711963SAfshin.Ardakani@Sun.COM dfs_setpriv(PRIV_OFF);
91811963SAfshin.Ardakani@Sun.COM dfs_path_free(&path);
91911963SAfshin.Ardakani@Sun.COM return (status);
92011963SAfshin.Ardakani@Sun.COM }
92111963SAfshin.Ardakani@Sun.COM
92211963SAfshin.Ardakani@Sun.COM /*
92311963SAfshin.Ardakani@Sun.COM * Takes a DFS path in UNC format (dfs_path) and parse it into a dfs_path_t
92411963SAfshin.Ardakani@Sun.COM * structure.
92511963SAfshin.Ardakani@Sun.COM *
92611963SAfshin.Ardakani@Sun.COM * dfs_path_free() MUST be called to free the allocated memory in this
92711963SAfshin.Ardakani@Sun.COM * function.
92811963SAfshin.Ardakani@Sun.COM *
92911963SAfshin.Ardakani@Sun.COM * Returns:
93011963SAfshin.Ardakani@Sun.COM *
93111963SAfshin.Ardakani@Sun.COM * ERROR_INVALID_PARAMETER path is not a valid UNC or not valid for the
93211963SAfshin.Ardakani@Sun.COM * specified object type
93311963SAfshin.Ardakani@Sun.COM * ERROR_NOT_ENOUGH_MEMORY not enough memory to peform the parse
93411963SAfshin.Ardakani@Sun.COM * ERROR_NOT_FOUND namespace specified does not exist
93511963SAfshin.Ardakani@Sun.COM */
93611963SAfshin.Ardakani@Sun.COM uint32_t
dfs_path_parse(dfs_path_t * path,const char * dfs_path,uint32_t path_type)93711963SAfshin.Ardakani@Sun.COM dfs_path_parse(dfs_path_t *path, const char *dfs_path, uint32_t path_type)
93811963SAfshin.Ardakani@Sun.COM {
93911963SAfshin.Ardakani@Sun.COM char rootdir[DFS_PATH_MAX];
94011963SAfshin.Ardakani@Sun.COM smb_unc_t *unc;
94111963SAfshin.Ardakani@Sun.COM uint32_t status = ERROR_SUCCESS;
94211963SAfshin.Ardakani@Sun.COM int rc;
94311963SAfshin.Ardakani@Sun.COM
94411963SAfshin.Ardakani@Sun.COM bzero(path, sizeof (dfs_path_t));
94511963SAfshin.Ardakani@Sun.COM unc = &path->p_unc;
94611963SAfshin.Ardakani@Sun.COM
94711963SAfshin.Ardakani@Sun.COM rc = smb_unc_init(dfs_path, unc);
94811963SAfshin.Ardakani@Sun.COM switch (rc) {
94911963SAfshin.Ardakani@Sun.COM case EINVAL:
95011963SAfshin.Ardakani@Sun.COM return (ERROR_INVALID_PARAMETER);
95111963SAfshin.Ardakani@Sun.COM case ENOMEM:
95211963SAfshin.Ardakani@Sun.COM return (ERROR_NOT_ENOUGH_MEMORY);
95311963SAfshin.Ardakani@Sun.COM default:
95411963SAfshin.Ardakani@Sun.COM break;
95511963SAfshin.Ardakani@Sun.COM }
95611963SAfshin.Ardakani@Sun.COM
95711963SAfshin.Ardakani@Sun.COM if (dfs_namespace_path(unc->unc_share, rootdir, DFS_PATH_MAX)
95811963SAfshin.Ardakani@Sun.COM != ERROR_SUCCESS) {
95911963SAfshin.Ardakani@Sun.COM smb_unc_free(unc);
96011963SAfshin.Ardakani@Sun.COM return (ERROR_NOT_FOUND);
96111963SAfshin.Ardakani@Sun.COM }
96211963SAfshin.Ardakani@Sun.COM
96311963SAfshin.Ardakani@Sun.COM if (path_type == DFS_OBJECT_ANY)
96411963SAfshin.Ardakani@Sun.COM path->p_type = (unc->unc_path != NULL)
96511963SAfshin.Ardakani@Sun.COM ? DFS_OBJECT_LINK : DFS_OBJECT_ROOT;
96611963SAfshin.Ardakani@Sun.COM else
96711963SAfshin.Ardakani@Sun.COM path->p_type = path_type;
96811963SAfshin.Ardakani@Sun.COM
96911963SAfshin.Ardakani@Sun.COM switch (path->p_type) {
97011963SAfshin.Ardakani@Sun.COM case DFS_OBJECT_LINK:
97111963SAfshin.Ardakani@Sun.COM if ((unc->unc_path == NULL) || (*unc->unc_path == '\0'))
97211963SAfshin.Ardakani@Sun.COM status = ERROR_NOT_FOUND;
97311963SAfshin.Ardakani@Sun.COM else
97411963SAfshin.Ardakani@Sun.COM (void) snprintf(path->p_fspath, sizeof (path->p_fspath),
97511963SAfshin.Ardakani@Sun.COM "%s/%s", rootdir, unc->unc_path);
97611963SAfshin.Ardakani@Sun.COM break;
97711963SAfshin.Ardakani@Sun.COM
97811963SAfshin.Ardakani@Sun.COM case DFS_OBJECT_ROOT:
97911963SAfshin.Ardakani@Sun.COM if (unc->unc_path == NULL)
98011963SAfshin.Ardakani@Sun.COM (void) strlcpy(path->p_fspath, rootdir,
98111963SAfshin.Ardakani@Sun.COM sizeof (path->p_fspath));
98211963SAfshin.Ardakani@Sun.COM else
98311963SAfshin.Ardakani@Sun.COM status = ERROR_INVALID_PARAMETER;
98411963SAfshin.Ardakani@Sun.COM break;
98511963SAfshin.Ardakani@Sun.COM
98611963SAfshin.Ardakani@Sun.COM default:
98711963SAfshin.Ardakani@Sun.COM status = ERROR_INVALID_PARAMETER;
98811963SAfshin.Ardakani@Sun.COM }
98911963SAfshin.Ardakani@Sun.COM
99011963SAfshin.Ardakani@Sun.COM if (status != ERROR_SUCCESS)
99111963SAfshin.Ardakani@Sun.COM smb_unc_free(unc);
99211963SAfshin.Ardakani@Sun.COM
99311963SAfshin.Ardakani@Sun.COM return (status);
99411963SAfshin.Ardakani@Sun.COM }
99511963SAfshin.Ardakani@Sun.COM
99611963SAfshin.Ardakani@Sun.COM /*
99711963SAfshin.Ardakani@Sun.COM * Frees the allocated memory for p_unc field of the passed path
99811963SAfshin.Ardakani@Sun.COM */
99911963SAfshin.Ardakani@Sun.COM void
dfs_path_free(dfs_path_t * path)100011963SAfshin.Ardakani@Sun.COM dfs_path_free(dfs_path_t *path)
100111963SAfshin.Ardakani@Sun.COM {
100211963SAfshin.Ardakani@Sun.COM if (path != NULL)
100311963SAfshin.Ardakani@Sun.COM smb_unc_free(&path->p_unc);
100411963SAfshin.Ardakani@Sun.COM }
100511963SAfshin.Ardakani@Sun.COM
100611963SAfshin.Ardakani@Sun.COM /*
100711963SAfshin.Ardakani@Sun.COM * Free the allocated memory for targets in the given info
100811963SAfshin.Ardakani@Sun.COM * structure
100911963SAfshin.Ardakani@Sun.COM */
101011963SAfshin.Ardakani@Sun.COM void
dfs_info_free(dfs_info_t * info)101111963SAfshin.Ardakani@Sun.COM dfs_info_free(dfs_info_t *info)
101211963SAfshin.Ardakani@Sun.COM {
101311963SAfshin.Ardakani@Sun.COM if (info)
101411963SAfshin.Ardakani@Sun.COM free(info->i_targets);
101511963SAfshin.Ardakani@Sun.COM }
101611963SAfshin.Ardakani@Sun.COM
101711963SAfshin.Ardakani@Sun.COM /*
101811963SAfshin.Ardakani@Sun.COM * Trace the given DFS info structure
101911963SAfshin.Ardakani@Sun.COM */
102011963SAfshin.Ardakani@Sun.COM void
dfs_info_trace(const char * msg,dfs_info_t * info)102111963SAfshin.Ardakani@Sun.COM dfs_info_trace(const char *msg, dfs_info_t *info)
102211963SAfshin.Ardakani@Sun.COM {
102311963SAfshin.Ardakani@Sun.COM dfs_target_t *t;
102411963SAfshin.Ardakani@Sun.COM int i;
102511963SAfshin.Ardakani@Sun.COM
102611963SAfshin.Ardakani@Sun.COM smb_tracef("%s", msg);
102711963SAfshin.Ardakani@Sun.COM if (info == NULL)
102811963SAfshin.Ardakani@Sun.COM return;
102911963SAfshin.Ardakani@Sun.COM
103011963SAfshin.Ardakani@Sun.COM smb_tracef("UNC\t%s", info->i_uncpath);
103111963SAfshin.Ardakani@Sun.COM smb_tracef("comment\t%s", info->i_comment);
103211963SAfshin.Ardakani@Sun.COM smb_tracef("GUID\t%s", info->i_guid);
103311963SAfshin.Ardakani@Sun.COM smb_tracef("state\t%X", info->i_state);
103411963SAfshin.Ardakani@Sun.COM smb_tracef("timeout\t%d", info->i_timeout);
103511963SAfshin.Ardakani@Sun.COM smb_tracef("props\t%X", info->i_propflags);
103611963SAfshin.Ardakani@Sun.COM smb_tracef("# targets\t%X", info->i_ntargets);
103711963SAfshin.Ardakani@Sun.COM
103811963SAfshin.Ardakani@Sun.COM if (info->i_targets == NULL)
103911963SAfshin.Ardakani@Sun.COM return;
104011963SAfshin.Ardakani@Sun.COM
104111963SAfshin.Ardakani@Sun.COM for (i = 0, t = info->i_targets; i < info->i_ntargets; i++, t++) {
104211963SAfshin.Ardakani@Sun.COM smb_tracef("[%d] \\\\%s\\%s", i, t->t_server, t->t_share);
104311963SAfshin.Ardakani@Sun.COM smb_tracef("[%d] state\t%X", i, t->t_state);
104411963SAfshin.Ardakani@Sun.COM smb_tracef("[%d] priority\t%d:%d", i, t->t_priority.p_class,
104511963SAfshin.Ardakani@Sun.COM t->t_priority.p_rank);
104611963SAfshin.Ardakani@Sun.COM }
104711963SAfshin.Ardakani@Sun.COM }
104811963SAfshin.Ardakani@Sun.COM
104911963SAfshin.Ardakani@Sun.COM /*
105011963SAfshin.Ardakani@Sun.COM * Search the path specified by 'relpath' to see if it contains
105111963SAfshin.Ardakani@Sun.COM * a DFS link starting from the last component. If a link is found
105211963SAfshin.Ardakani@Sun.COM * the full path is returned in 'linkpath'
105311963SAfshin.Ardakani@Sun.COM */
105411963SAfshin.Ardakani@Sun.COM static boolean_t
dfs_namespace_findlink(const char * name,char * relpath,char * linkpath,size_t bufsz)105511963SAfshin.Ardakani@Sun.COM dfs_namespace_findlink(const char *name, char *relpath,
105611963SAfshin.Ardakani@Sun.COM char *linkpath, size_t bufsz)
105711963SAfshin.Ardakani@Sun.COM {
105811963SAfshin.Ardakani@Sun.COM char rootdir[DFS_PATH_MAX];
105911963SAfshin.Ardakani@Sun.COM uint32_t stat;
106011963SAfshin.Ardakani@Sun.COM char *p;
106111963SAfshin.Ardakani@Sun.COM
106211963SAfshin.Ardakani@Sun.COM if (dfs_namespace_path(name, rootdir, DFS_PATH_MAX) != ERROR_SUCCESS)
106311963SAfshin.Ardakani@Sun.COM return (B_FALSE);
106411963SAfshin.Ardakani@Sun.COM
106511963SAfshin.Ardakani@Sun.COM (void) snprintf(linkpath, bufsz, "%s/%s", rootdir, relpath);
106611963SAfshin.Ardakani@Sun.COM
106711963SAfshin.Ardakani@Sun.COM for (;;) {
106811963SAfshin.Ardakani@Sun.COM if (dfs_link_stat(linkpath, &stat) != ERROR_SUCCESS)
106911963SAfshin.Ardakani@Sun.COM return (B_FALSE);
107011963SAfshin.Ardakani@Sun.COM
107111963SAfshin.Ardakani@Sun.COM if (stat == DFS_STAT_ISDFS)
107211963SAfshin.Ardakani@Sun.COM return (B_TRUE);
107311963SAfshin.Ardakani@Sun.COM
107411963SAfshin.Ardakani@Sun.COM if ((p = strrchr(relpath, '/')) == NULL)
107511963SAfshin.Ardakani@Sun.COM return (B_FALSE);
107611963SAfshin.Ardakani@Sun.COM *p = '\0';
107711963SAfshin.Ardakani@Sun.COM
107811963SAfshin.Ardakani@Sun.COM (void) snprintf(linkpath, bufsz, "%s/%s", rootdir, relpath);
107911963SAfshin.Ardakani@Sun.COM }
108011963SAfshin.Ardakani@Sun.COM
108111963SAfshin.Ardakani@Sun.COM /*NOTREACHED*/
108211963SAfshin.Ardakani@Sun.COM return (B_FALSE);
108311963SAfshin.Ardakani@Sun.COM }
108411963SAfshin.Ardakani@Sun.COM
108511963SAfshin.Ardakani@Sun.COM /*
108611963SAfshin.Ardakani@Sun.COM * Caches the specified namespace
108711963SAfshin.Ardakani@Sun.COM */
108811963SAfshin.Ardakani@Sun.COM static void *
dfs_namespace_cache(void * arg)108911963SAfshin.Ardakani@Sun.COM dfs_namespace_cache(void *arg)
109011963SAfshin.Ardakani@Sun.COM {
109111963SAfshin.Ardakani@Sun.COM char *share = arg;
109211963SAfshin.Ardakani@Sun.COM char uncpath[DFS_PATH_MAX];
109311963SAfshin.Ardakani@Sun.COM smb_share_t si;
109411963SAfshin.Ardakani@Sun.COM
109511963SAfshin.Ardakani@Sun.COM if (smb_shr_get(share, &si) != NERR_Success) {
109611963SAfshin.Ardakani@Sun.COM free(share);
109711963SAfshin.Ardakani@Sun.COM return (NULL);
109811963SAfshin.Ardakani@Sun.COM }
109911963SAfshin.Ardakani@Sun.COM
1100*12890SJoyce.McIntosh@Sun.COM /*
1101*12890SJoyce.McIntosh@Sun.COM * This check should be removed when multiple standalone
1102*12890SJoyce.McIntosh@Sun.COM * namespaces are supported.
1103*12890SJoyce.McIntosh@Sun.COM */
1104*12890SJoyce.McIntosh@Sun.COM (void) mutex_lock(&dfs_nsmtx);
1105*12890SJoyce.McIntosh@Sun.COM if (*dfs_cached_ns != '\0') {
1106*12890SJoyce.McIntosh@Sun.COM syslog(LOG_WARNING, "dfs: trying to load %s namespace."
1107*12890SJoyce.McIntosh@Sun.COM " Only one standalone namespace is supported."
1108*12890SJoyce.McIntosh@Sun.COM " A namespace is already exported for %s",
1109*12890SJoyce.McIntosh@Sun.COM share, dfs_cached_ns);
1110*12890SJoyce.McIntosh@Sun.COM (void) mutex_unlock(&dfs_nsmtx);
1111*12890SJoyce.McIntosh@Sun.COM free(share);
1112*12890SJoyce.McIntosh@Sun.COM return (NULL);
1113*12890SJoyce.McIntosh@Sun.COM }
1114*12890SJoyce.McIntosh@Sun.COM (void) strlcpy(dfs_cached_ns, share, sizeof (dfs_cached_ns));
1115*12890SJoyce.McIntosh@Sun.COM (void) smb_config_setnum(SMB_CI_DFS_STDROOT_NUM, 1);
1116*12890SJoyce.McIntosh@Sun.COM (void) mutex_unlock(&dfs_nsmtx);
1117*12890SJoyce.McIntosh@Sun.COM
111811963SAfshin.Ardakani@Sun.COM (void) snprintf(uncpath, DFS_PATH_MAX, "\\\\%s\\%s", dfs_nbname, share);
111911963SAfshin.Ardakani@Sun.COM (void) dfs_cache_add_byunc(uncpath, si.shr_path, DFS_OBJECT_ROOT);
112011963SAfshin.Ardakani@Sun.COM
112111963SAfshin.Ardakani@Sun.COM dfs_cache_populate(uncpath, si.shr_path);
112211963SAfshin.Ardakani@Sun.COM
112311963SAfshin.Ardakani@Sun.COM free(share);
112411963SAfshin.Ardakani@Sun.COM return (NULL);
112511963SAfshin.Ardakani@Sun.COM }
112611963SAfshin.Ardakani@Sun.COM
1127*12890SJoyce.McIntosh@Sun.COM /*
1128*12890SJoyce.McIntosh@Sun.COM * Checks whether the given name matches the name of
1129*12890SJoyce.McIntosh@Sun.COM * the cached namespace.
1130*12890SJoyce.McIntosh@Sun.COM */
1131*12890SJoyce.McIntosh@Sun.COM static boolean_t
dfs_namespace_iscached(const char * name)1132*12890SJoyce.McIntosh@Sun.COM dfs_namespace_iscached(const char *name)
1133*12890SJoyce.McIntosh@Sun.COM {
1134*12890SJoyce.McIntosh@Sun.COM boolean_t iscached;
1135*12890SJoyce.McIntosh@Sun.COM
1136*12890SJoyce.McIntosh@Sun.COM (void) mutex_lock(&dfs_nsmtx);
1137*12890SJoyce.McIntosh@Sun.COM iscached = (smb_strcasecmp(name, dfs_cached_ns, 0) == 0);
1138*12890SJoyce.McIntosh@Sun.COM (void) mutex_unlock(&dfs_nsmtx);
1139*12890SJoyce.McIntosh@Sun.COM
1140*12890SJoyce.McIntosh@Sun.COM return (iscached);
1141*12890SJoyce.McIntosh@Sun.COM }
1142*12890SJoyce.McIntosh@Sun.COM
114311963SAfshin.Ardakani@Sun.COM static int
dfs_root_add(const char * rootdir,dfs_info_t * info)114411963SAfshin.Ardakani@Sun.COM dfs_root_add(const char *rootdir, dfs_info_t *info)
114511963SAfshin.Ardakani@Sun.COM {
114611963SAfshin.Ardakani@Sun.COM uint32_t status = ERROR_INTERNAL_ERROR;
114711963SAfshin.Ardakani@Sun.COM int xfd;
114811963SAfshin.Ardakani@Sun.COM
114911963SAfshin.Ardakani@Sun.COM (void) rw_wrlock(&dfs_root_rwl);
115011963SAfshin.Ardakani@Sun.COM if ((xfd = dfs_root_xopen(rootdir, O_CREAT | O_TRUNC | O_RDWR)) > 0) {
115111963SAfshin.Ardakani@Sun.COM status = dfs_root_xwrite(xfd, info);
115211963SAfshin.Ardakani@Sun.COM dfs_root_xclose(xfd);
115311963SAfshin.Ardakani@Sun.COM }
115411963SAfshin.Ardakani@Sun.COM (void) rw_unlock(&dfs_root_rwl);
115511963SAfshin.Ardakani@Sun.COM
115611963SAfshin.Ardakani@Sun.COM return (status);
115711963SAfshin.Ardakani@Sun.COM }
115811963SAfshin.Ardakani@Sun.COM
115911963SAfshin.Ardakani@Sun.COM /*
116011963SAfshin.Ardakani@Sun.COM * Deletes the specified root information
116111963SAfshin.Ardakani@Sun.COM */
116211963SAfshin.Ardakani@Sun.COM static uint32_t
dfs_root_remove(const char * rootdir)116311963SAfshin.Ardakani@Sun.COM dfs_root_remove(const char *rootdir)
116411963SAfshin.Ardakani@Sun.COM {
116511963SAfshin.Ardakani@Sun.COM int attrdirfd;
116611963SAfshin.Ardakani@Sun.COM int err = 0;
116711963SAfshin.Ardakani@Sun.COM
116811963SAfshin.Ardakani@Sun.COM (void) rw_wrlock(&dfs_root_rwl);
116911963SAfshin.Ardakani@Sun.COM
117011963SAfshin.Ardakani@Sun.COM if ((attrdirfd = attropen(rootdir, ".", O_RDONLY)) > 0) {
117111963SAfshin.Ardakani@Sun.COM if (unlinkat(attrdirfd, DFS_ROOT_XATTR, 0) == -1) {
117211963SAfshin.Ardakani@Sun.COM if (errno != ENOENT)
117311963SAfshin.Ardakani@Sun.COM err = errno;
117411963SAfshin.Ardakani@Sun.COM }
117511963SAfshin.Ardakani@Sun.COM (void) close(attrdirfd);
117611963SAfshin.Ardakani@Sun.COM } else {
117711963SAfshin.Ardakani@Sun.COM err = errno;
117811963SAfshin.Ardakani@Sun.COM }
117911963SAfshin.Ardakani@Sun.COM
118011963SAfshin.Ardakani@Sun.COM (void) rw_unlock(&dfs_root_rwl);
118111963SAfshin.Ardakani@Sun.COM
118211963SAfshin.Ardakani@Sun.COM if (err != 0) {
118311963SAfshin.Ardakani@Sun.COM syslog(LOG_DEBUG, "dfs: failed to remove root info %s (%d)",
118411963SAfshin.Ardakani@Sun.COM rootdir, err);
118511963SAfshin.Ardakani@Sun.COM return (ERROR_INTERNAL_ERROR);
118611963SAfshin.Ardakani@Sun.COM }
118711963SAfshin.Ardakani@Sun.COM
118811963SAfshin.Ardakani@Sun.COM return (ERROR_SUCCESS);
118911963SAfshin.Ardakani@Sun.COM }
119011963SAfshin.Ardakani@Sun.COM
119111963SAfshin.Ardakani@Sun.COM /*
119211963SAfshin.Ardakani@Sun.COM * Opens DFS root directory's extended attribute with the given mode.
119311963SAfshin.Ardakani@Sun.COM */
119411963SAfshin.Ardakani@Sun.COM static int
dfs_root_xopen(const char * rootdir,int oflag)119511963SAfshin.Ardakani@Sun.COM dfs_root_xopen(const char *rootdir, int oflag)
119611963SAfshin.Ardakani@Sun.COM {
119711963SAfshin.Ardakani@Sun.COM int dfd;
119811963SAfshin.Ardakani@Sun.COM int xfd = -1;
119911963SAfshin.Ardakani@Sun.COM int err = 0;
120011963SAfshin.Ardakani@Sun.COM
120111963SAfshin.Ardakani@Sun.COM if ((dfd = open(rootdir, O_RDONLY)) > 0) {
120211963SAfshin.Ardakani@Sun.COM xfd = openat(dfd, DFS_ROOT_XATTR, oflag | O_XATTR, 0600);
120311963SAfshin.Ardakani@Sun.COM if (xfd == -1)
120411963SAfshin.Ardakani@Sun.COM err = errno;
120511963SAfshin.Ardakani@Sun.COM (void) close(dfd);
120611963SAfshin.Ardakani@Sun.COM } else {
120711963SAfshin.Ardakani@Sun.COM err = errno;
120811963SAfshin.Ardakani@Sun.COM }
120911963SAfshin.Ardakani@Sun.COM
121011963SAfshin.Ardakani@Sun.COM if (err != 0) {
121111963SAfshin.Ardakani@Sun.COM syslog(LOG_DEBUG, "dfs: failed to open root directory %s (%d)",
121211963SAfshin.Ardakani@Sun.COM rootdir, err);
121311963SAfshin.Ardakani@Sun.COM }
121411963SAfshin.Ardakani@Sun.COM
121511963SAfshin.Ardakani@Sun.COM return (xfd);
121611963SAfshin.Ardakani@Sun.COM }
121711963SAfshin.Ardakani@Sun.COM
121811963SAfshin.Ardakani@Sun.COM /*
121911963SAfshin.Ardakani@Sun.COM * Closes given extended attribute file descriptor
122011963SAfshin.Ardakani@Sun.COM */
122111963SAfshin.Ardakani@Sun.COM static void
dfs_root_xclose(int xfd)122211963SAfshin.Ardakani@Sun.COM dfs_root_xclose(int xfd)
122311963SAfshin.Ardakani@Sun.COM {
122411963SAfshin.Ardakani@Sun.COM (void) close(xfd);
122511963SAfshin.Ardakani@Sun.COM }
122611963SAfshin.Ardakani@Sun.COM
122711963SAfshin.Ardakani@Sun.COM /*
122811963SAfshin.Ardakani@Sun.COM * Writes the given DFS data in the DFS root directory's
122911963SAfshin.Ardakani@Sun.COM * extended attribute specified with xfd file descriptor.
123011963SAfshin.Ardakani@Sun.COM */
123111963SAfshin.Ardakani@Sun.COM static uint32_t
dfs_root_xwrite(int xfd,dfs_info_t * info)123211963SAfshin.Ardakani@Sun.COM dfs_root_xwrite(int xfd, dfs_info_t *info)
123311963SAfshin.Ardakani@Sun.COM {
123411963SAfshin.Ardakani@Sun.COM size_t nbytes;
123511963SAfshin.Ardakani@Sun.COM char *buf = NULL;
123611963SAfshin.Ardakani@Sun.COM size_t buflen;
123711963SAfshin.Ardakani@Sun.COM uint32_t status;
123811963SAfshin.Ardakani@Sun.COM
123911963SAfshin.Ardakani@Sun.COM if ((status = dfs_root_encode(info, &buf, &buflen)) != ERROR_SUCCESS)
124011963SAfshin.Ardakani@Sun.COM return (status);
124111963SAfshin.Ardakani@Sun.COM
124211963SAfshin.Ardakani@Sun.COM (void) lseek(xfd, 0, SEEK_SET);
124311963SAfshin.Ardakani@Sun.COM nbytes = write(xfd, buf, buflen);
124411963SAfshin.Ardakani@Sun.COM free(buf);
124511963SAfshin.Ardakani@Sun.COM
124611963SAfshin.Ardakani@Sun.COM return ((nbytes == buflen) ? ERROR_SUCCESS : ERROR_INTERNAL_ERROR);
124711963SAfshin.Ardakani@Sun.COM }
124811963SAfshin.Ardakani@Sun.COM
124911963SAfshin.Ardakani@Sun.COM /*
125011963SAfshin.Ardakani@Sun.COM * Reads DFS root information from its directory extended attribute
125111963SAfshin.Ardakani@Sun.COM * and parse it into given dfs_info_t structure
125211963SAfshin.Ardakani@Sun.COM */
125311963SAfshin.Ardakani@Sun.COM static uint32_t
dfs_root_xread(int xfd,dfs_info_t * info,uint32_t infolvl)125411963SAfshin.Ardakani@Sun.COM dfs_root_xread(int xfd, dfs_info_t *info, uint32_t infolvl)
125511963SAfshin.Ardakani@Sun.COM {
125611963SAfshin.Ardakani@Sun.COM struct stat statbuf;
125711963SAfshin.Ardakani@Sun.COM uint32_t status;
125811963SAfshin.Ardakani@Sun.COM char *buf;
125911963SAfshin.Ardakani@Sun.COM
126011963SAfshin.Ardakani@Sun.COM if (fstat(xfd, &statbuf) != 0)
126111963SAfshin.Ardakani@Sun.COM return (ERROR_INTERNAL_ERROR);
126211963SAfshin.Ardakani@Sun.COM
126311963SAfshin.Ardakani@Sun.COM if ((buf = malloc(statbuf.st_size)) == NULL)
126411963SAfshin.Ardakani@Sun.COM return (ERROR_NOT_ENOUGH_MEMORY);
126511963SAfshin.Ardakani@Sun.COM
126611963SAfshin.Ardakani@Sun.COM if (read(xfd, buf, statbuf.st_size) == statbuf.st_size)
126711963SAfshin.Ardakani@Sun.COM status = dfs_root_decode(info, buf, statbuf.st_size, infolvl);
126811963SAfshin.Ardakani@Sun.COM else
126911963SAfshin.Ardakani@Sun.COM status = ERROR_INTERNAL_ERROR;
127011963SAfshin.Ardakani@Sun.COM
127111963SAfshin.Ardakani@Sun.COM free(buf);
127211963SAfshin.Ardakani@Sun.COM return (status);
127311963SAfshin.Ardakani@Sun.COM }
127411963SAfshin.Ardakani@Sun.COM
127511963SAfshin.Ardakani@Sun.COM /*
127611963SAfshin.Ardakani@Sun.COM * Encodes (packs) DFS information in 'info' into a flat
127711963SAfshin.Ardakani@Sun.COM * buffer in a name-value format. This function allocates a
127811963SAfshin.Ardakani@Sun.COM * buffer with appropriate size to contain all the information
127911963SAfshin.Ardakani@Sun.COM * so the caller MUST free the allocated memory by calling free().
128011963SAfshin.Ardakani@Sun.COM */
128111963SAfshin.Ardakani@Sun.COM static uint32_t
dfs_root_encode(dfs_info_t * info,char ** buf,size_t * bufsz)128211963SAfshin.Ardakani@Sun.COM dfs_root_encode(dfs_info_t *info, char **buf, size_t *bufsz)
128311963SAfshin.Ardakani@Sun.COM {
128411963SAfshin.Ardakani@Sun.COM dfs_target_t *t;
128511963SAfshin.Ardakani@Sun.COM nvlist_t *nvl;
128611963SAfshin.Ardakani@Sun.COM int rc;
128711963SAfshin.Ardakani@Sun.COM
128811963SAfshin.Ardakani@Sun.COM if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0)
128911963SAfshin.Ardakani@Sun.COM return (ERROR_NOT_ENOUGH_MEMORY);
129011963SAfshin.Ardakani@Sun.COM
129111963SAfshin.Ardakani@Sun.COM rc = nvlist_add_string(nvl, "comment", info->i_comment);
129211963SAfshin.Ardakani@Sun.COM rc |= nvlist_add_string(nvl, "guid", info->i_guid);
129311963SAfshin.Ardakani@Sun.COM rc |= nvlist_add_uint32(nvl, "state", info->i_state);
129411963SAfshin.Ardakani@Sun.COM rc |= nvlist_add_uint32(nvl, "timeout", info->i_timeout);
129511963SAfshin.Ardakani@Sun.COM rc |= nvlist_add_uint32(nvl, "propflags", info->i_propflags);
129611963SAfshin.Ardakani@Sun.COM t = info->i_targets;
129711963SAfshin.Ardakani@Sun.COM rc |= nvlist_add_string(nvl, "t_server", t->t_server);
129811963SAfshin.Ardakani@Sun.COM rc |= nvlist_add_string(nvl, "t_share", t->t_share);
129911963SAfshin.Ardakani@Sun.COM rc |= nvlist_add_uint32(nvl, "t_state", t->t_state);
1300*12890SJoyce.McIntosh@Sun.COM rc |= nvlist_add_uint32(nvl, "t_priority_class",
1301*12890SJoyce.McIntosh@Sun.COM t->t_priority.p_class);
1302*12890SJoyce.McIntosh@Sun.COM rc |= nvlist_add_uint16(nvl, "t_priority_rank",
1303*12890SJoyce.McIntosh@Sun.COM t->t_priority.p_rank);
130411963SAfshin.Ardakani@Sun.COM
130511963SAfshin.Ardakani@Sun.COM if (rc == 0)
130611963SAfshin.Ardakani@Sun.COM rc = nvlist_pack(nvl, buf, bufsz, NV_ENCODE_NATIVE, 0);
130711963SAfshin.Ardakani@Sun.COM
130811963SAfshin.Ardakani@Sun.COM nvlist_free(nvl);
130911963SAfshin.Ardakani@Sun.COM
131011963SAfshin.Ardakani@Sun.COM return ((rc == 0) ? ERROR_SUCCESS : ERROR_INTERNAL_ERROR);
131111963SAfshin.Ardakani@Sun.COM }
131211963SAfshin.Ardakani@Sun.COM
131311963SAfshin.Ardakani@Sun.COM /*
131411963SAfshin.Ardakani@Sun.COM * Decodes (unpack) provided buffer which contains a list of name-value
131511963SAfshin.Ardakani@Sun.COM * pairs into given dfs_info_t structure
131611963SAfshin.Ardakani@Sun.COM */
131711963SAfshin.Ardakani@Sun.COM static uint32_t
dfs_root_decode(dfs_info_t * info,char * buf,size_t bufsz,uint32_t infolvl)131811963SAfshin.Ardakani@Sun.COM dfs_root_decode(dfs_info_t *info, char *buf, size_t bufsz, uint32_t infolvl)
131911963SAfshin.Ardakani@Sun.COM {
132011963SAfshin.Ardakani@Sun.COM nvlist_t *nvl;
132111963SAfshin.Ardakani@Sun.COM char *cmnt, *guid;
132211963SAfshin.Ardakani@Sun.COM char *t_server, *t_share;
132311963SAfshin.Ardakani@Sun.COM uint32_t t_state;
1324*12890SJoyce.McIntosh@Sun.COM uint32_t t_priority_class;
1325*12890SJoyce.McIntosh@Sun.COM uint16_t t_priority_rank;
1326*12890SJoyce.McIntosh@Sun.COM boolean_t decode_priority = B_FALSE;
132711963SAfshin.Ardakani@Sun.COM int rc;
132811963SAfshin.Ardakani@Sun.COM
132911963SAfshin.Ardakani@Sun.COM if (nvlist_unpack(buf, bufsz, &nvl, 0) != 0)
133011963SAfshin.Ardakani@Sun.COM return (ERROR_INTERNAL_ERROR);
133111963SAfshin.Ardakani@Sun.COM
133211963SAfshin.Ardakani@Sun.COM rc = nvlist_lookup_string(nvl, "comment", &cmnt);
133311963SAfshin.Ardakani@Sun.COM rc |= nvlist_lookup_string(nvl, "guid", &guid);
133411963SAfshin.Ardakani@Sun.COM rc |= nvlist_lookup_uint32(nvl, "state", &info->i_state);
133511963SAfshin.Ardakani@Sun.COM rc |= nvlist_lookup_uint32(nvl, "timeout", &info->i_timeout);
133611963SAfshin.Ardakani@Sun.COM rc |= nvlist_lookup_uint32(nvl, "propflags", &info->i_propflags);
133711963SAfshin.Ardakani@Sun.COM
133811963SAfshin.Ardakani@Sun.COM if (rc != 0) {
133911963SAfshin.Ardakani@Sun.COM nvlist_free(nvl);
134011963SAfshin.Ardakani@Sun.COM return (ERROR_INTERNAL_ERROR);
134111963SAfshin.Ardakani@Sun.COM }
134211963SAfshin.Ardakani@Sun.COM
134311963SAfshin.Ardakani@Sun.COM (void) strlcpy(info->i_comment, (cmnt) ? cmnt : "",
134411963SAfshin.Ardakani@Sun.COM sizeof (info->i_comment));
134511963SAfshin.Ardakani@Sun.COM (void) strlcpy(info->i_guid, (guid) ? guid : "", sizeof (info->i_guid));
134611963SAfshin.Ardakani@Sun.COM
134711963SAfshin.Ardakani@Sun.COM info->i_targets = NULL;
134811963SAfshin.Ardakani@Sun.COM info->i_ntargets = 1;
134911963SAfshin.Ardakani@Sun.COM
135011963SAfshin.Ardakani@Sun.COM switch (infolvl) {
135111963SAfshin.Ardakani@Sun.COM case DFS_INFO_ALL:
135211963SAfshin.Ardakani@Sun.COM case 3:
135311963SAfshin.Ardakani@Sun.COM case 4:
1354*12890SJoyce.McIntosh@Sun.COM /* need target information */
1355*12890SJoyce.McIntosh@Sun.COM break;
135611963SAfshin.Ardakani@Sun.COM case 6:
135711963SAfshin.Ardakani@Sun.COM case 9:
1358*12890SJoyce.McIntosh@Sun.COM /* need target and priority information */
1359*12890SJoyce.McIntosh@Sun.COM decode_priority = B_TRUE;
136011963SAfshin.Ardakani@Sun.COM break;
136111963SAfshin.Ardakani@Sun.COM default:
136211963SAfshin.Ardakani@Sun.COM nvlist_free(nvl);
136311963SAfshin.Ardakani@Sun.COM return (ERROR_SUCCESS);
136411963SAfshin.Ardakani@Sun.COM }
136511963SAfshin.Ardakani@Sun.COM
136611963SAfshin.Ardakani@Sun.COM info->i_targets = malloc(sizeof (dfs_target_t));
136711963SAfshin.Ardakani@Sun.COM if (info->i_targets == NULL) {
136811963SAfshin.Ardakani@Sun.COM nvlist_free(nvl);
136911963SAfshin.Ardakani@Sun.COM return (ERROR_NOT_ENOUGH_MEMORY);
137011963SAfshin.Ardakani@Sun.COM }
137111963SAfshin.Ardakani@Sun.COM
137211963SAfshin.Ardakani@Sun.COM rc = nvlist_lookup_string(nvl, "t_server", &t_server);
137311963SAfshin.Ardakani@Sun.COM rc |= nvlist_lookup_string(nvl, "t_share", &t_share);
137411963SAfshin.Ardakani@Sun.COM rc |= nvlist_lookup_uint32(nvl, "t_state", &t_state);
137511963SAfshin.Ardakani@Sun.COM if (rc != 0) {
137611963SAfshin.Ardakani@Sun.COM nvlist_free(nvl);
137711963SAfshin.Ardakani@Sun.COM free(info->i_targets);
137811963SAfshin.Ardakani@Sun.COM return (ERROR_INTERNAL_ERROR);
137911963SAfshin.Ardakani@Sun.COM }
138011963SAfshin.Ardakani@Sun.COM dfs_target_init(info->i_targets, t_server, t_share, t_state);
138111963SAfshin.Ardakani@Sun.COM
1382*12890SJoyce.McIntosh@Sun.COM if (decode_priority) {
1383*12890SJoyce.McIntosh@Sun.COM rc = nvlist_lookup_uint32(nvl, "t_priority_class",
1384*12890SJoyce.McIntosh@Sun.COM &t_priority_class);
1385*12890SJoyce.McIntosh@Sun.COM if (rc == 0)
1386*12890SJoyce.McIntosh@Sun.COM rc = nvlist_lookup_uint16(nvl, "t_priority_rank",
1387*12890SJoyce.McIntosh@Sun.COM &t_priority_rank);
1388*12890SJoyce.McIntosh@Sun.COM
1389*12890SJoyce.McIntosh@Sun.COM if (rc != 0 && rc != ENOENT) {
1390*12890SJoyce.McIntosh@Sun.COM nvlist_free(nvl);
1391*12890SJoyce.McIntosh@Sun.COM free(info->i_targets);
1392*12890SJoyce.McIntosh@Sun.COM return (ERROR_INTERNAL_ERROR);
1393*12890SJoyce.McIntosh@Sun.COM } else if (rc == 0) {
1394*12890SJoyce.McIntosh@Sun.COM info->i_targets->t_priority.p_class = t_priority_class;
1395*12890SJoyce.McIntosh@Sun.COM info->i_targets->t_priority.p_rank = t_priority_rank;
1396*12890SJoyce.McIntosh@Sun.COM }
1397*12890SJoyce.McIntosh@Sun.COM }
1398*12890SJoyce.McIntosh@Sun.COM
139911963SAfshin.Ardakani@Sun.COM nvlist_free(nvl);
140011963SAfshin.Ardakani@Sun.COM return (ERROR_SUCCESS);
140111963SAfshin.Ardakani@Sun.COM }
140211963SAfshin.Ardakani@Sun.COM
140311963SAfshin.Ardakani@Sun.COM /*
140411963SAfshin.Ardakani@Sun.COM * Determines if the passed state is valid for a DFS root
140511963SAfshin.Ardakani@Sun.COM *
140611963SAfshin.Ardakani@Sun.COM * This is based on test results against Win2003 and in some cases
140711963SAfshin.Ardakani@Sun.COM * does not match [MS-DFSNM] spec.
140811963SAfshin.Ardakani@Sun.COM */
140911963SAfshin.Ardakani@Sun.COM static uint32_t
dfs_root_isvalidstate(uint32_t state)141011963SAfshin.Ardakani@Sun.COM dfs_root_isvalidstate(uint32_t state)
141111963SAfshin.Ardakani@Sun.COM {
141211963SAfshin.Ardakani@Sun.COM switch (state) {
141311963SAfshin.Ardakani@Sun.COM case DFS_VOLUME_STATE_OK:
141411963SAfshin.Ardakani@Sun.COM case DFS_VOLUME_STATE_RESYNCHRONIZE:
141511963SAfshin.Ardakani@Sun.COM return (ERROR_SUCCESS);
141611963SAfshin.Ardakani@Sun.COM
141711963SAfshin.Ardakani@Sun.COM case DFS_VOLUME_STATE_INCONSISTENT:
141811963SAfshin.Ardakani@Sun.COM case DFS_VOLUME_STATE_FORCE_SYNC:
141911963SAfshin.Ardakani@Sun.COM return (ERROR_INVALID_PARAMETER);
142011963SAfshin.Ardakani@Sun.COM
142111963SAfshin.Ardakani@Sun.COM case DFS_VOLUME_STATE_OFFLINE:
142211963SAfshin.Ardakani@Sun.COM case DFS_VOLUME_STATE_ONLINE:
142311963SAfshin.Ardakani@Sun.COM case DFS_VOLUME_STATE_STANDBY:
142411963SAfshin.Ardakani@Sun.COM return (ERROR_NOT_SUPPORTED);
142511963SAfshin.Ardakani@Sun.COM default:
142611963SAfshin.Ardakani@Sun.COM break;
142711963SAfshin.Ardakani@Sun.COM }
142811963SAfshin.Ardakani@Sun.COM
142911963SAfshin.Ardakani@Sun.COM return (ERROR_INVALID_PARAMETER);
143011963SAfshin.Ardakani@Sun.COM }
143111963SAfshin.Ardakani@Sun.COM
143211963SAfshin.Ardakani@Sun.COM /*
143311963SAfshin.Ardakani@Sun.COM * Decodes the link info from given string buffer (buf) into
143411963SAfshin.Ardakani@Sun.COM * dfs_info_t structure.
143511963SAfshin.Ardakani@Sun.COM */
143611963SAfshin.Ardakani@Sun.COM static uint32_t
dfs_link_decode(dfs_info_t * info,char * buf,uint32_t infolvl)143711963SAfshin.Ardakani@Sun.COM dfs_link_decode(dfs_info_t *info, char *buf, uint32_t infolvl)
143811963SAfshin.Ardakani@Sun.COM {
143911963SAfshin.Ardakani@Sun.COM char *lfield[DFS_LINK_HDR_NFIELDS];
144011963SAfshin.Ardakani@Sun.COM dfs_target_t *t;
144111963SAfshin.Ardakani@Sun.COM uint32_t linkver;
144211963SAfshin.Ardakani@Sun.COM uint32_t cmntlen;
144311963SAfshin.Ardakani@Sun.COM uint32_t cpylen;
144411963SAfshin.Ardakani@Sun.COM int i, j;
144511963SAfshin.Ardakani@Sun.COM
144611963SAfshin.Ardakani@Sun.COM /*
144711963SAfshin.Ardakani@Sun.COM * Header format
144811963SAfshin.Ardakani@Sun.COM * ver:state:prop:timeout:guid:ntarget:cmntlen:comment:
144911963SAfshin.Ardakani@Sun.COM */
145011963SAfshin.Ardakani@Sun.COM for (i = 0; i < DFS_LINK_HDR_NFIELDS; i++) {
145111963SAfshin.Ardakani@Sun.COM if ((lfield[i] = strsep((char **)&buf, ":")) == NULL)
145211963SAfshin.Ardakani@Sun.COM return (ERROR_INVALID_DATA);
145311963SAfshin.Ardakani@Sun.COM }
145411963SAfshin.Ardakani@Sun.COM
145511963SAfshin.Ardakani@Sun.COM i = 0;
145611963SAfshin.Ardakani@Sun.COM linkver = strtoul(lfield[i++], NULL, 10);
145711963SAfshin.Ardakani@Sun.COM if (linkver != DFS_LINK_V1)
145811963SAfshin.Ardakani@Sun.COM return (ERROR_INVALID_DATA);
145911963SAfshin.Ardakani@Sun.COM
146011963SAfshin.Ardakani@Sun.COM info->i_state = strtoul(lfield[i++], NULL, 10);
146111963SAfshin.Ardakani@Sun.COM info->i_propflags = strtoul(lfield[i++], NULL, 10);
146211963SAfshin.Ardakani@Sun.COM info->i_timeout = strtoul(lfield[i++], NULL, 10);
146311963SAfshin.Ardakani@Sun.COM (void) strlcpy(info->i_guid, lfield[i++], sizeof (info->i_guid));
146411963SAfshin.Ardakani@Sun.COM info->i_ntargets = strtoul(lfield[i++], NULL, 10);
146511963SAfshin.Ardakani@Sun.COM info->i_targets = NULL;
146611963SAfshin.Ardakani@Sun.COM
146711963SAfshin.Ardakani@Sun.COM cpylen = cmntlen = strtoul(lfield[i++], NULL, 10);
146811963SAfshin.Ardakani@Sun.COM
146911963SAfshin.Ardakani@Sun.COM if (cmntlen > sizeof (info->i_comment))
147011963SAfshin.Ardakani@Sun.COM cpylen = sizeof (info->i_comment);
147111963SAfshin.Ardakani@Sun.COM else if (cmntlen != 0)
147211963SAfshin.Ardakani@Sun.COM cpylen = cmntlen + 1;
147311963SAfshin.Ardakani@Sun.COM
147411963SAfshin.Ardakani@Sun.COM (void) strlcpy(info->i_comment, buf, cpylen);
147511963SAfshin.Ardakani@Sun.COM buf += (cmntlen + 1);
147611963SAfshin.Ardakani@Sun.COM
147711963SAfshin.Ardakani@Sun.COM switch (infolvl) {
147811963SAfshin.Ardakani@Sun.COM case DFS_INFO_ALL:
147911963SAfshin.Ardakani@Sun.COM case 3:
148011963SAfshin.Ardakani@Sun.COM case 4:
148111963SAfshin.Ardakani@Sun.COM case 6:
148211963SAfshin.Ardakani@Sun.COM case 9:
148311963SAfshin.Ardakani@Sun.COM /* need target information */
148411963SAfshin.Ardakani@Sun.COM break;
148511963SAfshin.Ardakani@Sun.COM default:
148611963SAfshin.Ardakani@Sun.COM return (ERROR_SUCCESS);
148711963SAfshin.Ardakani@Sun.COM }
148811963SAfshin.Ardakani@Sun.COM
148911963SAfshin.Ardakani@Sun.COM info->i_targets = calloc(info->i_ntargets, sizeof (dfs_target_t));
149011963SAfshin.Ardakani@Sun.COM if (info->i_targets == NULL)
149111963SAfshin.Ardakani@Sun.COM return (ERROR_NOT_ENOUGH_MEMORY);
149211963SAfshin.Ardakani@Sun.COM
149311963SAfshin.Ardakani@Sun.COM /*
149411963SAfshin.Ardakani@Sun.COM * Format for each target
149511963SAfshin.Ardakani@Sun.COM * server:share:state:class:rank
149611963SAfshin.Ardakani@Sun.COM */
149711963SAfshin.Ardakani@Sun.COM for (i = 0, t = info->i_targets; i < info->i_ntargets; i++, t++) {
149811963SAfshin.Ardakani@Sun.COM for (j = 0; j < DFS_LINK_TRGT_NFIELDS; j++) {
149911963SAfshin.Ardakani@Sun.COM if ((lfield[j] = strsep((char **)&buf, ":")) == NULL) {
150011963SAfshin.Ardakani@Sun.COM dfs_info_free(info);
150111963SAfshin.Ardakani@Sun.COM return (ERROR_INVALID_DATA);
150211963SAfshin.Ardakani@Sun.COM }
150311963SAfshin.Ardakani@Sun.COM }
150411963SAfshin.Ardakani@Sun.COM
150511963SAfshin.Ardakani@Sun.COM (void) strlcpy(t->t_server, lfield[0], sizeof (t->t_server));
150611963SAfshin.Ardakani@Sun.COM (void) strlcpy(t->t_share, lfield[1], sizeof (t->t_share));
150711963SAfshin.Ardakani@Sun.COM t->t_state = strtoul(lfield[2], NULL, 10);
150811963SAfshin.Ardakani@Sun.COM t->t_priority.p_class = strtoul(lfield[3], NULL, 10);
150911963SAfshin.Ardakani@Sun.COM t->t_priority.p_rank = strtoul(lfield[4], NULL, 10);
151011963SAfshin.Ardakani@Sun.COM }
151111963SAfshin.Ardakani@Sun.COM
151211963SAfshin.Ardakani@Sun.COM return (ERROR_SUCCESS);
151311963SAfshin.Ardakani@Sun.COM }
151411963SAfshin.Ardakani@Sun.COM
151511963SAfshin.Ardakani@Sun.COM /*
151611963SAfshin.Ardakani@Sun.COM * Encodes given link information (info)
151711963SAfshin.Ardakani@Sun.COM */
151811963SAfshin.Ardakani@Sun.COM static uint32_t
dfs_link_encode(dfs_info_t * info,char * buf,size_t bufsz)151911963SAfshin.Ardakani@Sun.COM dfs_link_encode(dfs_info_t *info, char *buf, size_t bufsz)
152011963SAfshin.Ardakani@Sun.COM {
152111963SAfshin.Ardakani@Sun.COM char linkdata[MAXREPARSELEN];
152211963SAfshin.Ardakani@Sun.COM dfs_target_t *t;
152311963SAfshin.Ardakani@Sun.COM int i, sz;
152411963SAfshin.Ardakani@Sun.COM
152511963SAfshin.Ardakani@Sun.COM /*
152611963SAfshin.Ardakani@Sun.COM * Header format
152711963SAfshin.Ardakani@Sun.COM * ver:state:prop:timeout:guid:ntarget:cmntlen:comment
152811963SAfshin.Ardakani@Sun.COM */
152911963SAfshin.Ardakani@Sun.COM sz = snprintf(buf, bufsz, "%u:%u:%u:%u:%s:%u:%u:%s",
153011963SAfshin.Ardakani@Sun.COM DFS_LINK_V1, info->i_state, info->i_propflags, info->i_timeout,
153111963SAfshin.Ardakani@Sun.COM info->i_guid, info->i_ntargets,
153211963SAfshin.Ardakani@Sun.COM strlen(info->i_comment), info->i_comment);
153311963SAfshin.Ardakani@Sun.COM
153411963SAfshin.Ardakani@Sun.COM if (sz > bufsz) {
153511963SAfshin.Ardakani@Sun.COM syslog(LOG_WARNING, "dfs: link data is too large");
153611963SAfshin.Ardakani@Sun.COM dfs_info_trace("DFS link encode", info);
153711963SAfshin.Ardakani@Sun.COM return (ERROR_INTERNAL_ERROR);
153811963SAfshin.Ardakani@Sun.COM }
153911963SAfshin.Ardakani@Sun.COM
154011963SAfshin.Ardakani@Sun.COM /*
154111963SAfshin.Ardakani@Sun.COM * Format for each target
154211963SAfshin.Ardakani@Sun.COM * :server:share:state:class:rank
154311963SAfshin.Ardakani@Sun.COM */
154411963SAfshin.Ardakani@Sun.COM bufsz -= sz;
154511963SAfshin.Ardakani@Sun.COM for (i = 0, t = info->i_targets; i < info->i_ntargets; i++, t++) {
154611963SAfshin.Ardakani@Sun.COM if (strchr(t->t_server, ':') || strchr(t->t_share, ':'))
154711963SAfshin.Ardakani@Sun.COM return (ERROR_INVALID_NAME);
154811963SAfshin.Ardakani@Sun.COM
154911963SAfshin.Ardakani@Sun.COM sz = snprintf(linkdata, MAXREPARSELEN, ":%s:%s:%u:%u:%u",
155011963SAfshin.Ardakani@Sun.COM t->t_server, t->t_share, t->t_state,
155111963SAfshin.Ardakani@Sun.COM t->t_priority.p_class, t->t_priority.p_rank);
155211963SAfshin.Ardakani@Sun.COM if (sz > bufsz) {
155311963SAfshin.Ardakani@Sun.COM syslog(LOG_WARNING, "dfs: link data is too large");
155411963SAfshin.Ardakani@Sun.COM dfs_info_trace("DFS link encode", info);
155511963SAfshin.Ardakani@Sun.COM return (ERROR_INTERNAL_ERROR);
155611963SAfshin.Ardakani@Sun.COM }
155711963SAfshin.Ardakani@Sun.COM (void) strcat(buf, linkdata);
155811963SAfshin.Ardakani@Sun.COM bufsz -= sz;
155911963SAfshin.Ardakani@Sun.COM }
156011963SAfshin.Ardakani@Sun.COM
156111963SAfshin.Ardakani@Sun.COM return (ERROR_SUCCESS);
156211963SAfshin.Ardakani@Sun.COM }
156311963SAfshin.Ardakani@Sun.COM
156411963SAfshin.Ardakani@Sun.COM /*
156511963SAfshin.Ardakani@Sun.COM * Stores given information for the specified link
156611963SAfshin.Ardakani@Sun.COM */
156711963SAfshin.Ardakani@Sun.COM static uint32_t
dfs_link_commit(const char * path,dfs_info_t * info)156811963SAfshin.Ardakani@Sun.COM dfs_link_commit(const char *path, dfs_info_t *info)
156911963SAfshin.Ardakani@Sun.COM {
157011963SAfshin.Ardakani@Sun.COM char linkdata[MAXREPARSELEN];
157111963SAfshin.Ardakani@Sun.COM uint32_t status;
157211963SAfshin.Ardakani@Sun.COM int rc;
157311963SAfshin.Ardakani@Sun.COM
157411963SAfshin.Ardakani@Sun.COM status = dfs_link_encode(info, linkdata, MAXREPARSELEN);
157511963SAfshin.Ardakani@Sun.COM if (status == ERROR_SUCCESS) {
157611963SAfshin.Ardakani@Sun.COM rc = smb_reparse_svcadd(path, DFS_REPARSE_SVCTYPE, linkdata);
157711963SAfshin.Ardakani@Sun.COM if (rc != 0)
157811963SAfshin.Ardakani@Sun.COM status = ERROR_INTERNAL_ERROR;
157911963SAfshin.Ardakani@Sun.COM }
158011963SAfshin.Ardakani@Sun.COM
158111963SAfshin.Ardakani@Sun.COM return (status);
158211963SAfshin.Ardakani@Sun.COM }
158311963SAfshin.Ardakani@Sun.COM
158411963SAfshin.Ardakani@Sun.COM /*
158511963SAfshin.Ardakani@Sun.COM * Determines if the passed state is valid for a link
158611963SAfshin.Ardakani@Sun.COM */
158711963SAfshin.Ardakani@Sun.COM static boolean_t
dfs_link_isvalidstate(uint32_t state)158811963SAfshin.Ardakani@Sun.COM dfs_link_isvalidstate(uint32_t state)
158911963SAfshin.Ardakani@Sun.COM {
159011963SAfshin.Ardakani@Sun.COM return (state == DFS_VOLUME_STATE_OK ||
159111963SAfshin.Ardakani@Sun.COM state == DFS_VOLUME_STATE_OFFLINE ||
159211963SAfshin.Ardakani@Sun.COM state == DFS_VOLUME_STATE_ONLINE);
159311963SAfshin.Ardakani@Sun.COM }
159411963SAfshin.Ardakani@Sun.COM
159511963SAfshin.Ardakani@Sun.COM /*
159611963SAfshin.Ardakani@Sun.COM * Initializes the given target structure (t) with provided information.
159711963SAfshin.Ardakani@Sun.COM */
159811963SAfshin.Ardakani@Sun.COM static void
dfs_target_init(dfs_target_t * t,const char * srv,const char * share,uint32_t state)159911963SAfshin.Ardakani@Sun.COM dfs_target_init(dfs_target_t *t, const char *srv, const char *share,
160011963SAfshin.Ardakani@Sun.COM uint32_t state)
160111963SAfshin.Ardakani@Sun.COM {
160211963SAfshin.Ardakani@Sun.COM (void) strlcpy(t->t_server, (srv) ? srv : "", sizeof (t->t_server));
160311963SAfshin.Ardakani@Sun.COM (void) strlcpy(t->t_share, (share) ? share : "", sizeof (t->t_share));
160411963SAfshin.Ardakani@Sun.COM t->t_state = state;
160511963SAfshin.Ardakani@Sun.COM t->t_priority.p_class = DfsSiteCostNormalPriorityClass;
160611963SAfshin.Ardakani@Sun.COM t->t_priority.p_rank = 0;
160711963SAfshin.Ardakani@Sun.COM }
160811963SAfshin.Ardakani@Sun.COM
160911963SAfshin.Ardakani@Sun.COM /*
161011963SAfshin.Ardakani@Sun.COM * Lookup the specified target (server, share) in the given
161111963SAfshin.Ardakani@Sun.COM * target list (targets). If there is a match its index is
161211963SAfshin.Ardakani@Sun.COM * returned, otherwise -1 will be returned.
161311963SAfshin.Ardakani@Sun.COM */
161411963SAfshin.Ardakani@Sun.COM static int
dfs_target_find(dfs_target_t * targets,uint32_t ntargets,const char * server,const char * share)161511963SAfshin.Ardakani@Sun.COM dfs_target_find(dfs_target_t *targets, uint32_t ntargets,
161611963SAfshin.Ardakani@Sun.COM const char *server, const char *share)
161711963SAfshin.Ardakani@Sun.COM {
161811963SAfshin.Ardakani@Sun.COM dfs_target_t *t;
161911963SAfshin.Ardakani@Sun.COM int i;
162011963SAfshin.Ardakani@Sun.COM
162111963SAfshin.Ardakani@Sun.COM for (i = 0, t = targets; i < ntargets; i++, t++) {
162211963SAfshin.Ardakani@Sun.COM if ((smb_strcasecmp(t->t_server, server, 0) == 0) &&
162311963SAfshin.Ardakani@Sun.COM (smb_strcasecmp(t->t_share, share, 0) == 0))
162411963SAfshin.Ardakani@Sun.COM return (i);
162511963SAfshin.Ardakani@Sun.COM }
162611963SAfshin.Ardakani@Sun.COM
162711963SAfshin.Ardakani@Sun.COM return (-1);
162811963SAfshin.Ardakani@Sun.COM }
162911963SAfshin.Ardakani@Sun.COM
163011963SAfshin.Ardakani@Sun.COM /*
163111963SAfshin.Ardakani@Sun.COM * Determines if the passed state is valid for a link/root target
163211963SAfshin.Ardakani@Sun.COM */
163311963SAfshin.Ardakani@Sun.COM static boolean_t
dfs_target_isvalidstate(uint32_t state)163411963SAfshin.Ardakani@Sun.COM dfs_target_isvalidstate(uint32_t state)
163511963SAfshin.Ardakani@Sun.COM {
163611963SAfshin.Ardakani@Sun.COM return (state == DFS_STORAGE_STATE_ONLINE ||
163711963SAfshin.Ardakani@Sun.COM state == DFS_STORAGE_STATE_OFFLINE);
163811963SAfshin.Ardakani@Sun.COM }
163911963SAfshin.Ardakani@Sun.COM
164011963SAfshin.Ardakani@Sun.COM /*
164111963SAfshin.Ardakani@Sun.COM * Cache compare function, the key is UNC path
164211963SAfshin.Ardakani@Sun.COM */
164311963SAfshin.Ardakani@Sun.COM static int
dfs_cache_cmp(const void * p1,const void * p2)164411963SAfshin.Ardakani@Sun.COM dfs_cache_cmp(const void *p1, const void *p2)
164511963SAfshin.Ardakani@Sun.COM {
164611963SAfshin.Ardakani@Sun.COM smb_cache_node_t *cn1 = (smb_cache_node_t *)p1;
164711963SAfshin.Ardakani@Sun.COM smb_cache_node_t *cn2 = (smb_cache_node_t *)p2;
164811963SAfshin.Ardakani@Sun.COM dfs_nscnode_t *dn1 = cn1->cn_data;
164911963SAfshin.Ardakani@Sun.COM dfs_nscnode_t *dn2 = cn2->cn_data;
165011963SAfshin.Ardakani@Sun.COM int rc;
165111963SAfshin.Ardakani@Sun.COM
165211963SAfshin.Ardakani@Sun.COM rc = smb_strcasecmp(dn1->nsc_uncpath, dn2->nsc_uncpath, 0);
165311963SAfshin.Ardakani@Sun.COM
165411963SAfshin.Ardakani@Sun.COM if (rc < 0)
165511963SAfshin.Ardakani@Sun.COM return (-1);
165611963SAfshin.Ardakani@Sun.COM
165711963SAfshin.Ardakani@Sun.COM if (rc > 0)
165811963SAfshin.Ardakani@Sun.COM return (1);
165911963SAfshin.Ardakani@Sun.COM
166011963SAfshin.Ardakani@Sun.COM return (0);
166111963SAfshin.Ardakani@Sun.COM }
166211963SAfshin.Ardakani@Sun.COM
166311963SAfshin.Ardakani@Sun.COM /*
166411963SAfshin.Ardakani@Sun.COM * Adds an entry with given UNC and filesystem path and the specified
166511963SAfshin.Ardakani@Sun.COM * entry type (i.e. root/link) to the namespace cache.
166611963SAfshin.Ardakani@Sun.COM */
166711963SAfshin.Ardakani@Sun.COM static uint32_t
dfs_cache_add_byunc(const char * uncpath,const char * fspath,uint32_t type)166811963SAfshin.Ardakani@Sun.COM dfs_cache_add_byunc(const char *uncpath, const char *fspath, uint32_t type)
166911963SAfshin.Ardakani@Sun.COM {
167011963SAfshin.Ardakani@Sun.COM dfs_nscnode_t *dn;
167111963SAfshin.Ardakani@Sun.COM uint32_t status = ERROR_SUCCESS;
167211963SAfshin.Ardakani@Sun.COM
167311963SAfshin.Ardakani@Sun.COM if ((dn = malloc(sizeof (dfs_nscnode_t))) == NULL)
167411963SAfshin.Ardakani@Sun.COM return (ERROR_NOT_ENOUGH_MEMORY);
167511963SAfshin.Ardakani@Sun.COM
167611963SAfshin.Ardakani@Sun.COM (void) strlcpy(dn->nsc_uncpath, uncpath, sizeof (dn->nsc_uncpath));
167711963SAfshin.Ardakani@Sun.COM (void) strlcpy(dn->nsc_fspath, fspath, sizeof (dn->nsc_fspath));
167811963SAfshin.Ardakani@Sun.COM dn->nsc_type = type;
167911963SAfshin.Ardakani@Sun.COM if (smb_cache_add(&dfs_nscache, dn, SMB_CACHE_ADD) != 0) {
168011963SAfshin.Ardakani@Sun.COM free(dn);
168111963SAfshin.Ardakani@Sun.COM status = ERROR_INTERNAL_ERROR;
168211963SAfshin.Ardakani@Sun.COM }
168311963SAfshin.Ardakani@Sun.COM
168411963SAfshin.Ardakani@Sun.COM return (status);
168511963SAfshin.Ardakani@Sun.COM }
168611963SAfshin.Ardakani@Sun.COM
168711963SAfshin.Ardakani@Sun.COM /*
168811963SAfshin.Ardakani@Sun.COM * starting from DFS root directory, scans the tree for DFS links
168911963SAfshin.Ardakani@Sun.COM * and adds them to the cache.
169011963SAfshin.Ardakani@Sun.COM */
169111963SAfshin.Ardakani@Sun.COM static void
dfs_cache_populate(const char * unc_prefix,const char * dir)169211963SAfshin.Ardakani@Sun.COM dfs_cache_populate(const char *unc_prefix, const char *dir)
169311963SAfshin.Ardakani@Sun.COM {
169411963SAfshin.Ardakani@Sun.COM char fspath[DFS_PATH_MAX];
169511963SAfshin.Ardakani@Sun.COM char uncpath[DFS_PATH_MAX];
169611963SAfshin.Ardakani@Sun.COM char *fname;
169711963SAfshin.Ardakani@Sun.COM int nentries, i;
169811963SAfshin.Ardakani@Sun.COM struct dirent **entry_list;
169911963SAfshin.Ardakani@Sun.COM uint32_t stat;
170011963SAfshin.Ardakani@Sun.COM
170111963SAfshin.Ardakani@Sun.COM nentries = scandir(dir, &entry_list, NULL, NULL);
170211963SAfshin.Ardakani@Sun.COM if (nentries == -1)
170311963SAfshin.Ardakani@Sun.COM return;
170411963SAfshin.Ardakani@Sun.COM
170511963SAfshin.Ardakani@Sun.COM for (i = 0; i < nentries; i++) {
170611963SAfshin.Ardakani@Sun.COM fname = entry_list[i]->d_name;
170711963SAfshin.Ardakani@Sun.COM
170811963SAfshin.Ardakani@Sun.COM if (strcmp(fname, ".") == 0 ||
170911963SAfshin.Ardakani@Sun.COM strcmp(fname, "..") == 0) {
171011963SAfshin.Ardakani@Sun.COM free(entry_list[i]);
171111963SAfshin.Ardakani@Sun.COM continue;
171211963SAfshin.Ardakani@Sun.COM }
171311963SAfshin.Ardakani@Sun.COM
171411963SAfshin.Ardakani@Sun.COM (void) snprintf(fspath, DFS_PATH_MAX, "%s/%s", dir, fname);
171511963SAfshin.Ardakani@Sun.COM (void) snprintf(uncpath, DFS_PATH_MAX, "%s\\%s", unc_prefix,
171611963SAfshin.Ardakani@Sun.COM fname);
171711963SAfshin.Ardakani@Sun.COM
171811963SAfshin.Ardakani@Sun.COM if (dfs_path_isdir(fspath)) {
171911963SAfshin.Ardakani@Sun.COM dfs_cache_populate(uncpath, fspath);
172011963SAfshin.Ardakani@Sun.COM } else if (dfs_link_stat(fspath, &stat) == ERROR_SUCCESS) {
172111963SAfshin.Ardakani@Sun.COM if (stat == DFS_STAT_ISDFS)
172211963SAfshin.Ardakani@Sun.COM (void) dfs_cache_add_byunc(uncpath, fspath,
172311963SAfshin.Ardakani@Sun.COM DFS_OBJECT_LINK);
172411963SAfshin.Ardakani@Sun.COM }
172511963SAfshin.Ardakani@Sun.COM
172611963SAfshin.Ardakani@Sun.COM free(entry_list[i]);
172711963SAfshin.Ardakani@Sun.COM }
172811963SAfshin.Ardakani@Sun.COM
172911963SAfshin.Ardakani@Sun.COM for (; i < nentries; i++)
173011963SAfshin.Ardakani@Sun.COM free(entry_list[i]);
173111963SAfshin.Ardakani@Sun.COM
173211963SAfshin.Ardakani@Sun.COM free(entry_list);
173311963SAfshin.Ardakani@Sun.COM }
173411963SAfshin.Ardakani@Sun.COM
173511963SAfshin.Ardakani@Sun.COM /*
1736*12890SJoyce.McIntosh@Sun.COM * If this namespace hasn't been cached then return
1737*12890SJoyce.McIntosh@Sun.COM * without flushing the cache; otherwise clear the
1738*12890SJoyce.McIntosh@Sun.COM * name and flush the cache.
1739*12890SJoyce.McIntosh@Sun.COM */
1740*12890SJoyce.McIntosh@Sun.COM static void
dfs_cache_flush(const char * name)1741*12890SJoyce.McIntosh@Sun.COM dfs_cache_flush(const char *name)
1742*12890SJoyce.McIntosh@Sun.COM {
1743*12890SJoyce.McIntosh@Sun.COM (void) mutex_lock(&dfs_nsmtx);
1744*12890SJoyce.McIntosh@Sun.COM if (smb_strcasecmp(name, dfs_cached_ns, 0) != 0) {
1745*12890SJoyce.McIntosh@Sun.COM (void) mutex_unlock(&dfs_nsmtx);
1746*12890SJoyce.McIntosh@Sun.COM return;
1747*12890SJoyce.McIntosh@Sun.COM }
1748*12890SJoyce.McIntosh@Sun.COM *dfs_cached_ns = '\0';
1749*12890SJoyce.McIntosh@Sun.COM (void) smb_config_setnum(SMB_CI_DFS_STDROOT_NUM, 0);
1750*12890SJoyce.McIntosh@Sun.COM (void) mutex_unlock(&dfs_nsmtx);
1751*12890SJoyce.McIntosh@Sun.COM
1752*12890SJoyce.McIntosh@Sun.COM smb_cache_flush(&dfs_nscache);
1753*12890SJoyce.McIntosh@Sun.COM }
1754*12890SJoyce.McIntosh@Sun.COM
1755*12890SJoyce.McIntosh@Sun.COM /*
1756*12890SJoyce.McIntosh@Sun.COM * Returns the number of cached namespaces
1757*12890SJoyce.McIntosh@Sun.COM */
1758*12890SJoyce.McIntosh@Sun.COM static uint32_t
dfs_cache_nscount(void)1759*12890SJoyce.McIntosh@Sun.COM dfs_cache_nscount(void)
1760*12890SJoyce.McIntosh@Sun.COM {
1761*12890SJoyce.McIntosh@Sun.COM uint32_t nscount;
1762*12890SJoyce.McIntosh@Sun.COM
1763*12890SJoyce.McIntosh@Sun.COM (void) mutex_lock(&dfs_nsmtx);
1764*12890SJoyce.McIntosh@Sun.COM nscount = (*dfs_cached_ns == '\0') ? 0 : 1;
1765*12890SJoyce.McIntosh@Sun.COM (void) mutex_unlock(&dfs_nsmtx);
1766*12890SJoyce.McIntosh@Sun.COM
1767*12890SJoyce.McIntosh@Sun.COM return (nscount);
1768*12890SJoyce.McIntosh@Sun.COM }
1769*12890SJoyce.McIntosh@Sun.COM
1770*12890SJoyce.McIntosh@Sun.COM /*
177111963SAfshin.Ardakani@Sun.COM * Determines whether the given path is a directory.
177211963SAfshin.Ardakani@Sun.COM */
177311963SAfshin.Ardakani@Sun.COM static boolean_t
dfs_path_isdir(const char * path)177411963SAfshin.Ardakani@Sun.COM dfs_path_isdir(const char *path)
177511963SAfshin.Ardakani@Sun.COM {
177611963SAfshin.Ardakani@Sun.COM struct stat statbuf;
177711963SAfshin.Ardakani@Sun.COM
177811963SAfshin.Ardakani@Sun.COM if (lstat(path, &statbuf) != 0)
177911963SAfshin.Ardakani@Sun.COM return (B_FALSE);
178011963SAfshin.Ardakani@Sun.COM
178111963SAfshin.Ardakani@Sun.COM return ((statbuf.st_mode & S_IFMT) == S_IFDIR);
178211963SAfshin.Ardakani@Sun.COM }
178311963SAfshin.Ardakani@Sun.COM
178411963SAfshin.Ardakani@Sun.COM /*
1785*12890SJoyce.McIntosh@Sun.COM * Validates the given state based on the object type (root/link), info
1786*12890SJoyce.McIntosh@Sun.COM * level, and whether it is the object's state or its target's state
178711963SAfshin.Ardakani@Sun.COM */
178811963SAfshin.Ardakani@Sun.COM static uint32_t
dfs_isvalidstate(uint32_t state,uint32_t type,boolean_t target,uint32_t infolvl)1789*12890SJoyce.McIntosh@Sun.COM dfs_isvalidstate(uint32_t state, uint32_t type, boolean_t target,
1790*12890SJoyce.McIntosh@Sun.COM uint32_t infolvl)
179111963SAfshin.Ardakani@Sun.COM {
179211963SAfshin.Ardakani@Sun.COM uint32_t status = ERROR_SUCCESS;
179311963SAfshin.Ardakani@Sun.COM
1794*12890SJoyce.McIntosh@Sun.COM switch (infolvl) {
1795*12890SJoyce.McIntosh@Sun.COM case 101:
1796*12890SJoyce.McIntosh@Sun.COM if (type == DFS_OBJECT_ROOT) {
1797*12890SJoyce.McIntosh@Sun.COM if (!target)
1798*12890SJoyce.McIntosh@Sun.COM return (dfs_root_isvalidstate(state));
179911963SAfshin.Ardakani@Sun.COM
180011963SAfshin.Ardakani@Sun.COM if (!dfs_target_isvalidstate(state))
180111963SAfshin.Ardakani@Sun.COM status = ERROR_INVALID_PARAMETER;
1802*12890SJoyce.McIntosh@Sun.COM else if (state == DFS_STORAGE_STATE_OFFLINE)
1803*12890SJoyce.McIntosh@Sun.COM status = ERROR_NOT_SUPPORTED;
1804*12890SJoyce.McIntosh@Sun.COM } else {
1805*12890SJoyce.McIntosh@Sun.COM if (!target) {
1806*12890SJoyce.McIntosh@Sun.COM if (!dfs_link_isvalidstate(state))
1807*12890SJoyce.McIntosh@Sun.COM status = ERROR_INVALID_PARAMETER;
1808*12890SJoyce.McIntosh@Sun.COM } else {
1809*12890SJoyce.McIntosh@Sun.COM if (!dfs_target_isvalidstate(state))
1810*12890SJoyce.McIntosh@Sun.COM status = ERROR_INVALID_PARAMETER;
1811*12890SJoyce.McIntosh@Sun.COM }
181211963SAfshin.Ardakani@Sun.COM }
1813*12890SJoyce.McIntosh@Sun.COM break;
1814*12890SJoyce.McIntosh@Sun.COM
1815*12890SJoyce.McIntosh@Sun.COM case 105:
1816*12890SJoyce.McIntosh@Sun.COM if (state == 0)
1817*12890SJoyce.McIntosh@Sun.COM return (ERROR_SUCCESS);
1818*12890SJoyce.McIntosh@Sun.COM
1819*12890SJoyce.McIntosh@Sun.COM if (type == DFS_OBJECT_ROOT) {
1820*12890SJoyce.McIntosh@Sun.COM switch (state) {
1821*12890SJoyce.McIntosh@Sun.COM case DFS_VOLUME_STATE_OK:
1822*12890SJoyce.McIntosh@Sun.COM case DFS_VOLUME_STATE_OFFLINE:
1823*12890SJoyce.McIntosh@Sun.COM case DFS_VOLUME_STATE_ONLINE:
1824*12890SJoyce.McIntosh@Sun.COM case DFS_VOLUME_STATE_RESYNCHRONIZE:
1825*12890SJoyce.McIntosh@Sun.COM case DFS_VOLUME_STATE_STANDBY:
1826*12890SJoyce.McIntosh@Sun.COM status = ERROR_NOT_SUPPORTED;
1827*12890SJoyce.McIntosh@Sun.COM break;
1828*12890SJoyce.McIntosh@Sun.COM
1829*12890SJoyce.McIntosh@Sun.COM default:
1830*12890SJoyce.McIntosh@Sun.COM status = ERROR_INVALID_PARAMETER;
1831*12890SJoyce.McIntosh@Sun.COM }
1832*12890SJoyce.McIntosh@Sun.COM } else {
1833*12890SJoyce.McIntosh@Sun.COM switch (state) {
1834*12890SJoyce.McIntosh@Sun.COM case DFS_VOLUME_STATE_OK:
1835*12890SJoyce.McIntosh@Sun.COM case DFS_VOLUME_STATE_OFFLINE:
1836*12890SJoyce.McIntosh@Sun.COM case DFS_VOLUME_STATE_ONLINE:
1837*12890SJoyce.McIntosh@Sun.COM break;
1838*12890SJoyce.McIntosh@Sun.COM
1839*12890SJoyce.McIntosh@Sun.COM case DFS_VOLUME_STATE_RESYNCHRONIZE:
1840*12890SJoyce.McIntosh@Sun.COM case DFS_VOLUME_STATE_STANDBY:
1841*12890SJoyce.McIntosh@Sun.COM status = ERROR_NOT_SUPPORTED;
1842*12890SJoyce.McIntosh@Sun.COM break;
1843*12890SJoyce.McIntosh@Sun.COM
1844*12890SJoyce.McIntosh@Sun.COM default:
1845*12890SJoyce.McIntosh@Sun.COM status = ERROR_INVALID_PARAMETER;
1846*12890SJoyce.McIntosh@Sun.COM }
1847*12890SJoyce.McIntosh@Sun.COM }
1848*12890SJoyce.McIntosh@Sun.COM break;
1849*12890SJoyce.McIntosh@Sun.COM
1850*12890SJoyce.McIntosh@Sun.COM default:
1851*12890SJoyce.McIntosh@Sun.COM status = ERROR_INVALID_LEVEL;
185211963SAfshin.Ardakani@Sun.COM }
185311963SAfshin.Ardakani@Sun.COM
185411963SAfshin.Ardakani@Sun.COM return (status);
185511963SAfshin.Ardakani@Sun.COM }
185611963SAfshin.Ardakani@Sun.COM
185711963SAfshin.Ardakani@Sun.COM /*
1858*12890SJoyce.McIntosh@Sun.COM * Validates the given property flag mask based on the object
1859*12890SJoyce.McIntosh@Sun.COM * type (root/link) and namespace flavor.
1860*12890SJoyce.McIntosh@Sun.COM */
1861*12890SJoyce.McIntosh@Sun.COM static uint32_t
dfs_isvalidpropflagmask(uint32_t propflag_mask,uint32_t type,uint32_t flavor)1862*12890SJoyce.McIntosh@Sun.COM dfs_isvalidpropflagmask(uint32_t propflag_mask, uint32_t type,
1863*12890SJoyce.McIntosh@Sun.COM uint32_t flavor)
1864*12890SJoyce.McIntosh@Sun.COM {
1865*12890SJoyce.McIntosh@Sun.COM uint32_t flgs_not_supported;
1866*12890SJoyce.McIntosh@Sun.COM
1867*12890SJoyce.McIntosh@Sun.COM flgs_not_supported = DFS_PROPERTY_FLAG_ROOT_SCALABILITY
1868*12890SJoyce.McIntosh@Sun.COM | DFS_PROPERTY_FLAG_CLUSTER_ENABLED
1869*12890SJoyce.McIntosh@Sun.COM | DFS_PROPERTY_FLAG_ABDE;
1870*12890SJoyce.McIntosh@Sun.COM
1871*12890SJoyce.McIntosh@Sun.COM if (flavor == DFS_VOLUME_FLAVOR_STANDALONE) {
1872*12890SJoyce.McIntosh@Sun.COM if (type == DFS_OBJECT_LINK)
1873*12890SJoyce.McIntosh@Sun.COM flgs_not_supported |= DFS_PROPERTY_FLAG_SITE_COSTING;
1874*12890SJoyce.McIntosh@Sun.COM if (propflag_mask & flgs_not_supported)
1875*12890SJoyce.McIntosh@Sun.COM return (ERROR_NOT_SUPPORTED);
1876*12890SJoyce.McIntosh@Sun.COM }
1877*12890SJoyce.McIntosh@Sun.COM
1878*12890SJoyce.McIntosh@Sun.COM return (ERROR_SUCCESS);
1879*12890SJoyce.McIntosh@Sun.COM }
1880*12890SJoyce.McIntosh@Sun.COM
1881*12890SJoyce.McIntosh@Sun.COM /*
188211963SAfshin.Ardakani@Sun.COM * Based on the specified information level (infolvl) copy parts of the
188311963SAfshin.Ardakani@Sun.COM * information provided through newinfo into the existing information
188411963SAfshin.Ardakani@Sun.COM * (info) for the given object.
188511963SAfshin.Ardakani@Sun.COM */
188611963SAfshin.Ardakani@Sun.COM static uint32_t
dfs_modinfo(uint32_t type,dfs_info_t * info,dfs_info_t * newinfo,uint32_t infolvl)188711963SAfshin.Ardakani@Sun.COM dfs_modinfo(uint32_t type, dfs_info_t *info, dfs_info_t *newinfo,
188811963SAfshin.Ardakani@Sun.COM uint32_t infolvl)
188911963SAfshin.Ardakani@Sun.COM {
189011963SAfshin.Ardakani@Sun.COM boolean_t target_op = B_FALSE;
189111963SAfshin.Ardakani@Sun.COM uint32_t status = ERROR_SUCCESS;
189211963SAfshin.Ardakani@Sun.COM uint32_t state;
189311963SAfshin.Ardakani@Sun.COM int target_idx;
189411963SAfshin.Ardakani@Sun.COM
189511963SAfshin.Ardakani@Sun.COM if (newinfo->i_targets != NULL) {
189611963SAfshin.Ardakani@Sun.COM target_idx = dfs_target_find(info->i_targets, info->i_ntargets,
189711963SAfshin.Ardakani@Sun.COM newinfo->i_targets->t_server, newinfo->i_targets->t_share);
189811963SAfshin.Ardakani@Sun.COM if (target_idx == -1)
189911963SAfshin.Ardakani@Sun.COM return (ERROR_FILE_NOT_FOUND);
190011963SAfshin.Ardakani@Sun.COM target_op = B_TRUE;
190111963SAfshin.Ardakani@Sun.COM }
190211963SAfshin.Ardakani@Sun.COM
190311963SAfshin.Ardakani@Sun.COM switch (infolvl) {
190411963SAfshin.Ardakani@Sun.COM case 100:
190511963SAfshin.Ardakani@Sun.COM (void) strlcpy(info->i_comment, newinfo->i_comment,
190611963SAfshin.Ardakani@Sun.COM sizeof (newinfo->i_comment));
190711963SAfshin.Ardakani@Sun.COM break;
190811963SAfshin.Ardakani@Sun.COM
190911963SAfshin.Ardakani@Sun.COM case 101:
191011963SAfshin.Ardakani@Sun.COM state = (target_op)
191111963SAfshin.Ardakani@Sun.COM ? newinfo->i_targets->t_state : newinfo->i_state;
1912*12890SJoyce.McIntosh@Sun.COM status = dfs_isvalidstate(state, type, target_op, 101);
191311963SAfshin.Ardakani@Sun.COM if (status != ERROR_SUCCESS)
191411963SAfshin.Ardakani@Sun.COM return (status);
191511963SAfshin.Ardakani@Sun.COM
191611963SAfshin.Ardakani@Sun.COM if (!target_op) {
191711963SAfshin.Ardakani@Sun.COM /*
191811963SAfshin.Ardakani@Sun.COM * states specified by this mask should not be stored
191911963SAfshin.Ardakani@Sun.COM */
192011963SAfshin.Ardakani@Sun.COM if (state & DFS_VOLUME_STATES_SRV_OPS)
192111963SAfshin.Ardakani@Sun.COM return (ERROR_SUCCESS);
192211963SAfshin.Ardakani@Sun.COM
192311963SAfshin.Ardakani@Sun.COM info->i_state = state;
192411963SAfshin.Ardakani@Sun.COM } else {
192511963SAfshin.Ardakani@Sun.COM info->i_targets[target_idx].t_state = state;
192611963SAfshin.Ardakani@Sun.COM }
192711963SAfshin.Ardakani@Sun.COM break;
192811963SAfshin.Ardakani@Sun.COM
192911963SAfshin.Ardakani@Sun.COM case 102:
193011963SAfshin.Ardakani@Sun.COM info->i_timeout = newinfo->i_timeout;
193111963SAfshin.Ardakani@Sun.COM break;
193211963SAfshin.Ardakani@Sun.COM
193311963SAfshin.Ardakani@Sun.COM case 103:
193411963SAfshin.Ardakani@Sun.COM info->i_propflags = newinfo->i_propflags;
193511963SAfshin.Ardakani@Sun.COM break;
193611963SAfshin.Ardakani@Sun.COM
193711963SAfshin.Ardakani@Sun.COM case 104:
193811963SAfshin.Ardakani@Sun.COM info->i_targets[target_idx].t_priority =
193911963SAfshin.Ardakani@Sun.COM newinfo->i_targets->t_priority;
194011963SAfshin.Ardakani@Sun.COM break;
194111963SAfshin.Ardakani@Sun.COM
194211963SAfshin.Ardakani@Sun.COM case 105:
1943*12890SJoyce.McIntosh@Sun.COM status = dfs_isvalidstate(newinfo->i_state, type, B_FALSE, 105);
1944*12890SJoyce.McIntosh@Sun.COM if (status != ERROR_SUCCESS)
1945*12890SJoyce.McIntosh@Sun.COM return (status);
1946*12890SJoyce.McIntosh@Sun.COM
1947*12890SJoyce.McIntosh@Sun.COM status = dfs_isvalidpropflagmask(newinfo->i_propflag_mask, type,
1948*12890SJoyce.McIntosh@Sun.COM newinfo->i_flavor);
1949*12890SJoyce.McIntosh@Sun.COM if (status != ERROR_SUCCESS)
1950*12890SJoyce.McIntosh@Sun.COM return (status);
1951*12890SJoyce.McIntosh@Sun.COM
195211963SAfshin.Ardakani@Sun.COM (void) strlcpy(info->i_comment, newinfo->i_comment,
195311963SAfshin.Ardakani@Sun.COM sizeof (newinfo->i_comment));
1954*12890SJoyce.McIntosh@Sun.COM if (newinfo->i_state != 0)
1955*12890SJoyce.McIntosh@Sun.COM info->i_state = newinfo->i_state;
195611963SAfshin.Ardakani@Sun.COM info->i_timeout = newinfo->i_timeout;
195711963SAfshin.Ardakani@Sun.COM info->i_propflags = newinfo->i_propflags;
195811963SAfshin.Ardakani@Sun.COM break;
195911963SAfshin.Ardakani@Sun.COM
196011963SAfshin.Ardakani@Sun.COM default:
196111963SAfshin.Ardakani@Sun.COM status = ERROR_INVALID_LEVEL;
196211963SAfshin.Ardakani@Sun.COM }
196311963SAfshin.Ardakani@Sun.COM
196411963SAfshin.Ardakani@Sun.COM return (status);
196511963SAfshin.Ardakani@Sun.COM }
1966