smb_kutil.c revision a90cf9f29973990687fa61de9f1f6ea22e924e40
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2015 Nexenta Systems, Inc. All rights reserved.
*/
#include <smbsrv/smb_kproto.h>
#include <smbsrv/smb_fsops.h>
#include <smbsrv/smb_vops.h>
#include <smbsrv/smb_idmap.h>
#include <sys/priv_names.h>
static void smb_avl_rele(smb_avl_t *);
time_t tzh_leapcnt = 0;
struct tm
struct tm {
int tm_sec;
int tm_min;
int tm_hour;
int tm_mday;
int tm_mon;
int tm_year;
int tm_wday;
int tm_yday;
int tm_isdst;
};
static const int days_in_month[] = {
31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
};
int
{
return (smb_wcequiv_strlen(str));
}
int
{
}
int
{
return (2);
return (1);
}
/*
*
* Convert old-style (DOS, LanMan) wildcard strings to NT style.
* This should ONLY happen to patterns that come from old clients,
* meaning dialect LANMAN2_1 etc. (dialect < NT_LM_0_12).
*
* ? is converted to >
* * is converted to < if it is followed by .
* . is converted to " if it is followed by ? or * or end of pattern
*
* Note: modifies pattern in place.
*/
void
smb_convert_wildcards(char *pattern)
{
char *p;
for (p = pattern; *p != '\0'; p++) {
switch (*p) {
case '?':
*p = '>';
break;
case '*':
if (p[1] == '.')
*p = '<';
break;
case '.':
if (p[1] == '?' || p[1] == '*' || p[1] == '\0')
*p = '\"';
break;
}
}
}
/*
* smb_sattr_check
*
* Check file attributes against a search attribute (sattr) mask.
*
* Normal files, which includes READONLY and ARCHIVE, always pass
* this check. If the DIRECTORY, HIDDEN or SYSTEM special attributes
* are set then they must appear in the search mask. The special
* attributes are inclusive, i.e. all special attributes that appear
* in sattr must also appear in the file attributes for the check to
* pass.
*
* The following examples show how this works:
*
* fileA: READONLY
* fileB: 0 (no attributes = normal file)
* fileC: READONLY, ARCHIVE
* fileD: HIDDEN
* fileE: READONLY, HIDDEN, SYSTEM
* dirA: DIRECTORY
*
* search attribute: 0
* Returns: fileA, fileB and fileC.
* search attribute: HIDDEN
* Returns: fileA, fileB, fileC and fileD.
* search attribute: SYSTEM
* Returns: fileA, fileB and fileC.
* search attribute: DIRECTORY
* Returns: fileA, fileB, fileC and dirA.
* search attribute: HIDDEN and SYSTEM
* Returns: fileA, fileB, fileC, fileD and fileE.
*
* Returns true if the file and sattr match; otherwise, returns false.
*/
{
if ((dosattr & FILE_ATTRIBUTE_DIRECTORY) &&
return (B_FALSE);
if ((dosattr & FILE_ATTRIBUTE_HIDDEN) &&
!(sattr & FILE_ATTRIBUTE_HIDDEN))
return (B_FALSE);
if ((dosattr & FILE_ATTRIBUTE_SYSTEM) &&
!(sattr & FILE_ATTRIBUTE_SYSTEM))
return (B_FALSE);
return (B_TRUE);
}
smb_get_boottime(void)
{
/* Unfortunately, the GZ doesn't set zone_boot_time. */
if (z->zone_id == GLOBAL_ZONEID)
return (boot_time);
return (z->zone_boot_time);
}
/*
* smb_idpool_increment
*
* This function increments the ID pool by doubling the current size. This
* function assumes the caller entered the mutex of the pool.
*/
static int
{
if (new_size <= SMB_IDPOOL_MAX_SIZE) {
if (new_pool) {
if (new_size >= SMB_IDPOOL_MAX_SIZE) {
/* id -1 made unavailable */
pool->id_free_counter--;
}
return (0);
}
}
return (-1);
}
/*
* smb_idpool_constructor
*
* This function initializes the pool structure provided.
*/
int
{
KM_SLEEP);
/* -1 id made unavailable */
return (0);
}
/*
* smb_idpool_destructor
*
* This function tears down and frees the resources associated with the
* pool provided.
*/
void
{
}
/*
* smb_idpool_alloc
*
* This function allocates an ID from the pool provided.
*/
int
{
uint32_t i;
return (-1);
}
while (i) {
while (bit) {
bit_idx++;
continue;
}
pool->id_free_counter--;
return (0);
}
pool->id_bit_idx = 0;
--i;
}
/*
* This section of code shouldn't be reached. If there are IDs
* available and none could be found there's a problem.
*/
ASSERT(0);
return (-1);
}
/*
* smb_idpool_free
*
* This function frees the ID provided.
*/
void
{
pool->id_free_counter++;
return;
}
/* Freeing a free ID. */
ASSERT(0);
}
/*
* Initialize the llist delete queue object cache.
*/
void
smb_llist_init(void)
{
if (smb_dtor_cache != NULL)
return;
}
/*
* Destroy the llist delete queue object cache.
*/
void
smb_llist_fini(void)
{
if (smb_dtor_cache != NULL) {
}
}
/*
* smb_llist_constructor
*
* This function initializes a locked list.
*/
void
{
ll->ll_deleteq_count = 0;
}
/*
* Flush the delete queue and destroy a locked list.
*/
void
{
}
/*
* Post an object to the delete queue. The delete queue will be processed
* during list exit or list destruction. Objects are often posted for
* deletion during list iteration (while the list is locked) but that is
* not required, and an object can be posted at any time.
*/
void
{
++ll->ll_deleteq_count;
}
/*
* Exit the list lock and process the delete queue.
*/
void
{
}
/*
* Flush the list delete queue. The mutex is dropped across the destructor
* call in case this leads to additional objects being posted to the delete
* queue.
*/
void
{
if (ll->ll_flushing) {
return;
}
--ll->ll_deleteq_count;
}
}
/*
* smb_llist_upgrade
*
* This function tries to upgrade the lock of the locked list. It assumes the
* locked has already been entered in RW_READER mode. It first tries using the
* Solaris function rw_tryupgrade(). If that call fails the lock is released
* and reentered in RW_WRITER mode. In that last case a window is opened during
* which the contents of the list may have changed. The return code indicates
* whether or not the list was modified when the lock was exited.
*/
int smb_llist_upgrade(
{
return (0);
}
}
/*
* smb_llist_insert_head
*
* This function inserts the object passed a the beginning of the list. This
* function assumes the lock of the list has already been entered.
*/
void
void *obj)
{
}
/*
* smb_llist_insert_tail
*
* This function appends to the object passed to the list. This function assumes
* the lock of the list has already been entered.
*
*/
void
void *obj)
{
}
/*
* smb_llist_remove
*
* This function removes the object passed from the list. This function assumes
* the lock of the list has already been entered.
*/
void
void *obj)
{
}
/*
* smb_llist_get_count
*
* This function returns the number of elements in the specified list.
*/
{
}
/*
* smb_slist_constructor
*
* Synchronized list constructor.
*/
void
{
}
/*
* smb_slist_destructor
*
* Synchronized list destructor.
*/
void
{
}
/*
* smb_slist_insert_head
*
* This function inserts the object passed a the beginning of the list.
*/
void
void *obj)
{
}
/*
* smb_slist_insert_tail
*
* This function appends the object passed to the list.
*/
void
void *obj)
{
}
/*
* smb_llist_remove
*
* This function removes the object passed by the caller from the list.
*/
void
void *obj)
{
}
}
/*
* smb_slist_move_tail
*
* This function transfers all the contents of the synchronized list to the
* list_t provided. It returns the number of objects transferred.
*/
{
if (sl->sl_waiting) {
}
}
return (rv);
}
/*
* smb_slist_obj_move
*
* This function moves an object from one list to the end of the other list. It
* assumes the mutex of each list has been entered.
*/
void
void *obj)
{
}
}
/*
* smb_slist_wait_for_empty
*
* This function waits for a list to be emptied.
*/
void
{
}
}
/*
* smb_slist_exit
*
* This function exits the muetx of the list and signal the condition variable
* if the list is empty.
*/
void
{
}
}
/* smb_thread_... moved to smb_thread.c */
/*
* smb_rwx_init
*/
void
{
}
/*
* smb_rwx_destroy
*/
void
{
}
/*
* smb_rwx_rwexit
*/
void
{
if (rwx->rwx_waiting) {
}
}
}
/*
* smb_rwx_rwupgrade
*/
{
return (RW_WRITER);
}
}
return (RW_READER);
}
/*
* smb_rwx_rwrestore
*/
void
{
return;
}
if (rwx->rwx_waiting) {
}
}
/*
* smb_rwx_wait
*
* This function assumes the smb_rwx lock was enter in RW_READER or RW_WRITER
* mode. It will:
*
* 1) release the lock and save its current mode.
* 2) wait until the condition variable is signaled. This can happen for
* 2 reasons: When a writer releases the lock or when the time out (if
* provided) expires.
* 3) re-acquire the lock in the mode saved in (1).
*/
int
{
int rc = 1;
} else {
}
if (rwx->rwx_waiting) {
if (timeout == -1) {
} else {
}
}
return (rc);
}
/* smb_idmap_... moved to smb_idmap.c */
{
return (0);
return (nt_time + NT_TIME_BIAS);
}
void
{
return;
}
/*
* Can't represent times less than or equal NT_TIME_BIAS,
* so convert them to the oldest date we can store.
* Note that time zero is "special" being converted
* both directions as 0:0 (unix-to-nt, nt-to-unix).
*/
if (nt_time <= NT_TIME_BIAS) {
return;
}
nt_time -= NT_TIME_BIAS;
}
/*
* smb_time_gmt_to_local, smb_time_local_to_gmt
*
* Apply the gmt offset to convert between local time and gmt
*/
{
return (0);
}
{
return (0);
}
/*
* smb_time_dos_to_unix
*
* Convert SMB_DATE & SMB_TIME values to a unix timestamp.
*
* assigned value need not be changed. The behaviour when the
* generally treated like 0.
* If date or time is 0 or -1 the unix time is returned as 0
* so that the caller can identify and handle this special case.
*/
{
return (0);
}
return (smb_timegm(&atm));
}
void
{
int i;
if (ux_time == 0) {
*date_p = 0;
*time_p = 0;
return;
}
if (date_p) {
i = 0;
i <<= 4;
i <<= 5;
*date_p = (short)i;
}
if (time_p) {
i = 0;
i <<= 6;
i <<= 5;
*time_p = (short)i;
}
}
/*
* smb_gmtime_r
*
* Thread-safe version of smb_gmtime. Returns a null pointer if either
* input parameter is a null pointer. Otherwise returns a pointer
* to result.
*
* Day of the week calculation: the Epoch was a thursday.
*
* There are no timezone corrections so tm_isdst and tm_gmtoff are
* always zero, and the zone is always WET.
*/
struct tm *
{
int year;
int month;
int sec_per_month;
return (0);
tsec -= tzh_leapcnt;
year = EPOCH_YEAR;
(SECSPERDAY * DAYSPERNYEAR))) {
else
++year;
}
if (tsec < sec_per_month)
break;
tsec -= sec_per_month;
}
tsec %= SECSPERDAY;
tsec /= 60;
tsec /= 60;
return (result);
}
/*
* smb_timegm
*
* Converts the broken-down time in tm to a time value, i.e. the number
* of seconds since the Epoch (00:00:00 UTC, January 1, 1970). This is
* not a POSIX or ANSI function. Per the man page, the input values of
* tm_wday and tm_yday are ignored and, as the input data is assumed to
* represent GMT, we force tm_isdst and tm_gmtoff to 0.
*
* Before returning the clock time, we use smb_gmtime_r to set up tm_wday
* and tm_yday, and bring the other fields within normal range. I don't
* think this is really how it should be done but it's convenient for
* now.
*/
{
int dd;
int mm;
int yy;
int year;
if (tm == 0)
return (-1);
tsec = tzh_leapcnt;
else
}
dd += SECSPERDAY;
}
return (tsec);
}
/*
* smb_pad_align
*
* Returns the number of bytes required to pad an offset to the
* specified alignment.
*/
{
if (pad != 0)
return (pad);
}
/*
* smb_panic
*
* Logs the file name, function name and line number passed in and panics the
* system.
*/
void
{
}
/*
* Creates an AVL tree and initializes the given smb_avl_t
* structure using the passed args
*/
void
const smb_avl_nops_t *ops)
{
avl->avl_refcnt = 0;
sizeof (uint32_t));
}
/*
* Destroys the specified AVL tree.
* It waits for all the in-flight operations to finish
* before destroying the AVL.
*/
void
{
void *node;
return;
}
while (avl->avl_refcnt > 0)
}
/*
* Adds the given item to the AVL if it's
* not already there.
*
* Returns:
*
* ENOTACTIVE AVL is not in READY state
* EEXIST The item is already in AVL
*/
int
{
if (!smb_avl_hold(avl))
return (ENOTACTIVE);
return (EEXIST);
}
avl->avl_sequence++;
return (0);
}
/*
* Removes the given item from the AVL.
* If no reference is left on the item
* it will also be destroyed by calling the
* registered destroy operation.
*/
void
{
void *rm_item;
if (!smb_avl_hold(avl))
return;
return;
}
avl->avl_sequence++;
}
/*
* Looks up the AVL for the given item.
* If the item is found a hold on the object
* is taken before the pointer to it is
* returned to the caller. The caller MUST
* always call smb_avl_release() after it's done
* using the returned object to release the hold
* taken on the object.
*/
void *
{
if (!smb_avl_hold(avl))
return (NULL);
return (node);
}
/*
* The hold on the given object is released.
* This function MUST always be called after
* smb_avl_lookup() and smb_avl_iterate() for
* the returned object.
*
* If AVL is in DESTROYING state, the destroying
* thread will be notified.
*/
void
{
}
/*
* Initializes the given cursor for the AVL.
* The cursor will be used to iterate through the AVL
*/
void
{
}
/*
* Iterates through the AVL using the given cursor.
* It always starts at the beginning and then returns
* a pointer to the next object on each subsequent call.
*
* If a new object is added to or removed from the AVL
* between two calls to this function, the iteration
* will terminate prematurely.
*
* The caller MUST always call smb_avl_release() after it's
* done using the returned object to release the hold taken
* on the object.
*/
void *
{
void *node;
if (!smb_avl_hold(avl))
return (NULL);
return (NULL);
}
else
return (node);
}
/*
* Increments the AVL reference count in order to
* prevent the avl from being destroyed while it's
* being accessed.
*/
static boolean_t
{
return (B_FALSE);
}
avl->avl_refcnt++;
return (B_TRUE);
}
/*
* Decrements the AVL reference count to release the
* hold. If another thread is trying to destroy the
* AVL and is waiting for the reference count to become
* 0, it is signaled to wake up.
*/
static void
{
avl->avl_refcnt--;
}
/*
* smb_latency_init
*/
void
{
}
/*
* smb_latency_destroy
*/
void
{
}
/*
* smb_latency_add_sample
*
* Uses the new sample to calculate the new mean and standard deviation. The
* sample must be a scaled value.
*/
void
{
lat->ly_a_stddev =
}
lat->ly_d_stddev =
}
}
/*
* smb_srqueue_init
*/
void
{
}
/*
* smb_srqueue_destroy
*/
void
{
}
/*
* smb_srqueue_waitq_enter
*/
void
{
new = gethrtime_unscaled();
if (wcnt != 0) {
}
}
/*
* smb_srqueue_runq_exit
*/
void
{
new = gethrtime_unscaled();
}
/*
* smb_srqueue_waitq_to_runq
*/
void
{
new = gethrtime_unscaled();
if (rcnt != 0) {
}
}
/*
* smb_srqueue_update
*
* Takes a snapshot of the smb_sr_stat_t structure passed in.
*/
void
{
}
}
}
void
{
}
void
{
}
/*
* This threshold mechanism is used to limit the number of simultaneous
* named pipe connections, concurrent authentication conversations, etc.
* Requests that would take us over the threshold wait until either the
* resources are available (return zero) or timeout (return error).
*/
int
{
while (ct->ct_threshold != 0 &&
ct->ct_blocked_cnt++;
ct->ct_blocked_cnt--;
if (rem < 0) {
return (ETIME);
}
}
if (ct->ct_threshold == 0) {
return (ECANCELED);
}
ct->ct_active_cnt++;
return (0);
}
void
{
ct->ct_active_cnt--;
if (ct->ct_blocked_cnt)
}
void
{
ct->ct_threshold = 0;
}