#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/malloc.h>
#include <sys/time.h>
#include <sys/vnode.h>
#include <sys/sysctl.h>
#include <sys/kauth.h>
#include <sys/smb_apple.h>
#include <netsmb/smb.h>
#include <netsmb/smb_conn.h>
#include <netsmb/smb_subr.h>
#include <netsmb/smb_rq.h>
#include <netsmb/smb_dev.h>
#include <smbfs/smbfs.h>
#include <smbfs/smbfs_node.h>
#include <smbfs/smbfs_subr.h>
#include <netsmb/smb_converter.h>
uint64_t DIFF1970TO1601 = 11644473600ULL;
void
smb_time_NT2local(uint64_t nsec, struct timespec *tsp)
{
tsp->tv_sec = (long)(nsec / 10000000 - DIFF1970TO1601);
}
void
smb_time_local2NT(struct timespec *tsp, uint64_t *nsec, int fat_fstype)
{
if (fat_fstype)
*nsec = (((uint64_t)(tsp->tv_sec) & ~1) + DIFF1970TO1601) * (uint64_t)10000000;
else
*nsec = ((uint64_t)tsp->tv_sec + DIFF1970TO1601) * (uint64_t)10000000;
}
static int
smb_fphelp(struct smbmount *smp, struct mbchain *mbp, struct smbnode *np,
int usingUnicode, size_t *lenp)
{
struct smbnode *npstack[SMBFS_MAXPATHCOMP];
struct smbnode **npp = &npstack[0];
int i, error = 0;
if (smp->sm_args.path) {
if (usingUnicode)
error = mb_put_uint16le(mbp, '\\');
else
error = mb_put_uint8(mbp, '\\');
if (!error && lenp)
*lenp += (usingUnicode) ? 2 : 1;
if (!error)
error = mb_put_mem(mbp, (const char *)smp->sm_args.path,
smp->sm_args.path_len, MB_MSYSTEM);
if (!error && lenp)
*lenp += smp->sm_args.path_len;
}
if (np->n_flag & N_ISSTREAM)
np = np->n_parent;
i = 0;
while (np->n_parent) {
if (i++ == SMBFS_MAXPATHCOMP)
return ENAMETOOLONG;
*npp++ = np;
np = np->n_parent;
}
while (i--) {
np = *--npp;
if (usingUnicode)
error = mb_put_uint16le(mbp, '\\');
else
error = mb_put_uint8(mbp, '\\');
if (!error && lenp)
*lenp += (usingUnicode) ? 2 : 1;
if (error)
break;
lck_rw_lock_shared(&np->n_name_rwlock);
error = smb_put_dmem(mbp, (char *)(np->n_name), np->n_nmlen,
UTF_SFM_CONVERSIONS, usingUnicode, lenp);
lck_rw_unlock_shared(&np->n_name_rwlock);
if (error)
break;
}
return error;
}
int
smbfs_fullpath(struct mbchain *mbp, struct smbnode *dnp, const char *name,
size_t *lenp, int name_flags, int usingUnicode, uint8_t sep)
{
int error;
size_t len = 0;
if (lenp) {
len = *lenp;
*lenp = 0;
}
if (usingUnicode) {
error = mb_put_padbyte(mbp);
if (error)
return error;
}
if (dnp != NULL) {
struct smbmount *smp = dnp->n_mount;
error = smb_fphelp(smp, mbp, dnp, usingUnicode, lenp);
if (error)
return error;
if (((smp->sm_args.path == NULL) && (dnp->n_ino == 2) && !name))
name = "";
}
if (name) {
if (usingUnicode)
error = mb_put_uint16le(mbp, sep);
else
error = mb_put_uint8(mbp, sep);
if (!error && lenp)
*lenp += (usingUnicode) ? 2 : 1;
if (error)
return error;
error = smb_put_dmem(mbp, name, len, name_flags, usingUnicode, lenp);
if (error)
return error;
}
error = mb_put_uint8(mbp, 0);
if (usingUnicode && error == 0) {
error = mb_put_uint8(mbp, 0);
}
return error;
}
void
smbfs_create_start_path(struct smbmount *smp, struct smb_mount_args *args,
int usingUnicode)
{
int error;
args->path[MAXPATHLEN-1] = 0;
args->path_len = (args->path_len < MAXPATHLEN) ? args->path_len : (MAXPATHLEN - 1);
if (args->path[args->path_len - 1] == '/') {
args->path_len -= 1;
args->path[args->path_len] = 0;
}
smp->sm_args.path_len = (args->path_len * 2) + 2;
SMB_MALLOC(smp->sm_args.path, char *, smp->sm_args.path_len, M_TEMP, M_WAITOK);
if (smp->sm_args.path == NULL) {
smp->sm_args.path_len = 0;
return;
}
error = smb_convert_path_to_network(args->path, sizeof(args->path),
smp->sm_args.path, &smp->sm_args.path_len,
'\\', SMB_UTF_SFM_CONVERSIONS, usingUnicode);
if (error || (smp->sm_args.path_len == 0)) {
SMBDEBUG("Deep Path Failed %d\n", error);
SMB_FREE(smp->sm_args.path, M_TEMP);
smp->sm_args.path_len = 0;
}
}
char *
smbfs_ntwrkname_tolocal(const char *ntwrk_name, size_t *nmlen, int usingUnicode)
{
char *dst, *odst = NULL;
size_t inlen, outlen, length;
if (!nmlen || (*nmlen == 0))
return NULL;
if (usingUnicode) {
length = MIN(*nmlen * 9, SMB_MAXPKTLEN);
} else {
length = MIN(*nmlen * 3, SMB_MAXPKTLEN);
}
SMB_MALLOC(dst, char *, length+1, M_TEMP, M_WAITOK | M_ZERO);
outlen = length;
inlen = *nmlen;
odst = dst;
(void)smb_convert_from_network( &ntwrk_name, &inlen, &dst, &outlen,
UTF_SFM_CONVERSIONS, usingUnicode);
*nmlen = length - outlen;
odst[*nmlen] = 0;
return odst;
}
struct smb_share *
smb_get_share_with_reference(struct smbmount *smp)
{
struct smb_share *share = NULL;
lck_rw_lock_shared(&smp->sm_rw_sharelock);
share = smp->sm_share;
KASSERT(share, "smp->sm_share == NULL");
smb_share_ref(share);
lck_rw_unlock_shared(&smp->sm_rw_sharelock);
return share;
}