mirror of
https://github.com/m5stack/libsmb2.git
synced 2026-05-20 11:41:57 -07:00
936 lines
22 KiB
C
936 lines
22 KiB
C
/* -*- mode:c; tab-width:8; c-basic-offset:8; indent-tabs-mode:nil; -*- */
|
|
/*
|
|
Copyright (C) 2016 by Ronnie Sahlberg <ronniesahlberg@gmail.com>
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU Lesser General Public License as published by
|
|
the Free Software Foundation; either version 2.1 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU Lesser General Public License for more details.
|
|
|
|
You should have received a copy of the GNU Lesser General Public License
|
|
along with this program; if not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
#ifdef HAVE_CONFIG_H
|
|
#include "config.h"
|
|
#endif
|
|
|
|
#ifndef _GNU_SOURCE
|
|
#define _GNU_SOURCE
|
|
#endif
|
|
|
|
#ifdef HAVE_STDINT_H
|
|
#include <stdint.h>
|
|
#endif
|
|
|
|
#ifdef HAVE_STDLIB_H
|
|
#include <stdlib.h>
|
|
#endif
|
|
|
|
#include <errno.h>
|
|
|
|
#ifdef HAVE_SYS_POLL_H
|
|
#include <sys/poll.h>
|
|
#endif
|
|
|
|
#ifdef HAVE_POLL_H
|
|
#include <poll.h>
|
|
#endif
|
|
|
|
#ifdef HAVE_STRING_H
|
|
#include <string.h>
|
|
#endif
|
|
|
|
#include "compat.h"
|
|
|
|
#ifdef HAVE_TIME_H
|
|
#include <time.h>
|
|
#endif
|
|
|
|
#ifdef HAVE_SYS_TIME_H
|
|
#include <sys/time.h>
|
|
#endif
|
|
|
|
#include "smb2.h"
|
|
#include "libsmb2.h"
|
|
#include "libsmb2-raw.h"
|
|
#include "libsmb2-private.h"
|
|
|
|
static int wait_for_reply(struct smb2_context *smb2,
|
|
struct sync_cb_data *cb_data)
|
|
{
|
|
time_t t = time(NULL);
|
|
|
|
while (!cb_data->is_finished) {
|
|
struct pollfd pfd;
|
|
memset(&pfd, 0, sizeof(struct pollfd));
|
|
pfd.fd = smb2_get_fd(smb2);
|
|
pfd.events = smb2_which_events(smb2);
|
|
|
|
if (poll(&pfd, 1, 1000) < 0) {
|
|
smb2_set_error(smb2, "Poll failed");
|
|
return -1;
|
|
}
|
|
if (smb2->timeout) {
|
|
smb2_timeout_pdus(smb2);
|
|
}
|
|
if (!SMB2_VALID_SOCKET(smb2->fd) && ((time(NULL) - t) > (smb2->timeout)))
|
|
{
|
|
smb2_set_error(smb2, "Timeout expired and no connection exists\n");
|
|
return -1;
|
|
}
|
|
if (pfd.revents == 0) {
|
|
continue;
|
|
}
|
|
if (smb2_service(smb2, pfd.revents) < 0) {
|
|
smb2_set_error(smb2, "smb2_service failed with : "
|
|
"%s\n", smb2_get_error(smb2));
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void connect_cb(struct smb2_context *smb2, int status,
|
|
void *command_data, void *private_data)
|
|
{
|
|
struct sync_cb_data *cb_data = private_data;
|
|
|
|
if (cb_data->status == SMB2_STATUS_CANCELLED) {
|
|
if (cb_data != &smb2->connect_cb_data) {
|
|
free(cb_data);
|
|
}
|
|
return;
|
|
}
|
|
|
|
cb_data->is_finished = 1;
|
|
cb_data->status = status;
|
|
}
|
|
|
|
/*
|
|
* Connect to the server and mount the share.
|
|
*/
|
|
int smb2_connect_share(struct smb2_context *smb2,
|
|
const char *server,
|
|
const char *share,
|
|
const char *user)
|
|
{
|
|
struct sync_cb_data *cb_data;
|
|
int rc = 0;
|
|
|
|
cb_data = &smb2->connect_cb_data;
|
|
rc = smb2_connect_share_async(smb2, server, share, user, connect_cb, cb_data);
|
|
if (rc < 0) {
|
|
goto out;
|
|
}
|
|
|
|
rc = wait_for_reply(smb2, cb_data);
|
|
if (rc < 0) {
|
|
cb_data->status = SMB2_STATUS_CANCELLED;
|
|
return rc;
|
|
}
|
|
|
|
rc = cb_data->status;
|
|
out:
|
|
|
|
return rc;
|
|
}
|
|
|
|
/*
|
|
* Disconnect from share
|
|
*/
|
|
int smb2_disconnect_share(struct smb2_context *smb2)
|
|
{
|
|
struct sync_cb_data *cb_data;
|
|
int rc = 0;
|
|
|
|
cb_data = &smb2->connect_cb_data;
|
|
|
|
rc = smb2_disconnect_share_async(smb2, connect_cb, cb_data);
|
|
if (rc < 0) {
|
|
goto out;
|
|
}
|
|
|
|
rc = wait_for_reply(smb2, cb_data);
|
|
if (rc < 0) {
|
|
cb_data->status = SMB2_STATUS_CANCELLED;
|
|
return rc;
|
|
}
|
|
|
|
rc = cb_data->status;
|
|
out:
|
|
|
|
return rc;
|
|
}
|
|
|
|
/*
|
|
* opendir()
|
|
*/
|
|
static void opendir_cb(struct smb2_context *smb2, int status,
|
|
void *command_data, void *private_data)
|
|
{
|
|
struct sync_cb_data *cb_data = private_data;
|
|
|
|
if (status == SMB2_STATUS_SHUTDOWN) {
|
|
return;
|
|
}
|
|
if (cb_data->status == SMB2_STATUS_CANCELLED) {
|
|
return;
|
|
}
|
|
if (status) {
|
|
cb_data->status = status;
|
|
}
|
|
cb_data->is_finished = 1;
|
|
cb_data->ptr = command_data;
|
|
}
|
|
|
|
struct smb2dir *smb2_opendir(struct smb2_context *smb2, const char *path)
|
|
{
|
|
struct sync_cb_data *cb_data;
|
|
struct smb2dir *dir;
|
|
|
|
cb_data = calloc(1, sizeof(struct sync_cb_data));
|
|
if (cb_data == NULL) {
|
|
smb2_set_error(smb2, "Failed to allocate sync_cb_data");
|
|
return NULL;
|
|
}
|
|
|
|
if (smb2_opendir_async(smb2, path,
|
|
opendir_cb, cb_data) != 0) {
|
|
smb2_set_error(smb2, "smb2_opendir_async failed");
|
|
free(cb_data);
|
|
return NULL;
|
|
}
|
|
|
|
if (wait_for_reply(smb2, cb_data) < 0) {
|
|
cb_data->status = SMB2_STATUS_CANCELLED;
|
|
free(cb_data);
|
|
return NULL;
|
|
}
|
|
|
|
dir = cb_data->ptr;
|
|
if (dir) {
|
|
/* Give ownership of cb_data to dir. It will be freed when dir is freed */
|
|
dir->free_cb_data = free;
|
|
} else {
|
|
free(cb_data);
|
|
}
|
|
return dir;
|
|
}
|
|
|
|
/*
|
|
* open()
|
|
*/
|
|
static void open_cb(struct smb2_context *smb2, int status,
|
|
void *command_data, void *private_data)
|
|
{
|
|
struct sync_cb_data *cb_data = private_data;
|
|
|
|
if (cb_data->status == SMB2_STATUS_CANCELLED) {
|
|
free(cb_data);
|
|
return;
|
|
}
|
|
|
|
cb_data->is_finished = 1;
|
|
cb_data->ptr = command_data;
|
|
}
|
|
|
|
struct smb2fh *smb2_open(struct smb2_context *smb2, const char *path, int flags)
|
|
{
|
|
struct sync_cb_data *cb_data;
|
|
void *ptr;
|
|
|
|
cb_data = calloc(1, sizeof(struct sync_cb_data));
|
|
if (cb_data == NULL) {
|
|
smb2_set_error(smb2, "Failed to allocate sync_cb_data");
|
|
return NULL;
|
|
}
|
|
|
|
if (smb2_open_async(smb2, path, flags,
|
|
open_cb, cb_data) != 0) {
|
|
smb2_set_error(smb2, "smb2_open_async failed");
|
|
free(cb_data);
|
|
return NULL;
|
|
}
|
|
|
|
if (wait_for_reply(smb2, cb_data) < 0) {
|
|
cb_data->status = SMB2_STATUS_CANCELLED;
|
|
return NULL;
|
|
}
|
|
|
|
ptr = cb_data->ptr;
|
|
free(cb_data);
|
|
return ptr;
|
|
}
|
|
|
|
/*
|
|
* close()
|
|
*/
|
|
static void close_cb(struct smb2_context *smb2, int status,
|
|
void *command_data, void *private_data)
|
|
{
|
|
struct sync_cb_data *cb_data = private_data;
|
|
|
|
if (status == SMB2_STATUS_SHUTDOWN) {
|
|
return;
|
|
}
|
|
if (cb_data->status == SMB2_STATUS_CANCELLED) {
|
|
free(cb_data);
|
|
return;
|
|
}
|
|
|
|
cb_data->is_finished = 1;
|
|
cb_data->status = status;
|
|
}
|
|
|
|
int smb2_close(struct smb2_context *smb2, struct smb2fh *fh)
|
|
{
|
|
struct sync_cb_data *cb_data;
|
|
int rc = 0;
|
|
|
|
cb_data = calloc(1, sizeof(struct sync_cb_data));
|
|
if (cb_data == NULL) {
|
|
smb2_set_error(smb2, "Failed to allocate sync_cb_data");
|
|
return -ENOMEM;
|
|
}
|
|
|
|
rc = smb2_close_async(smb2, fh, close_cb, cb_data);
|
|
if (rc < 0) {
|
|
goto out;
|
|
}
|
|
|
|
rc = wait_for_reply(smb2, cb_data);
|
|
if (rc < 0) {
|
|
cb_data->status = SMB2_STATUS_CANCELLED;
|
|
goto out;
|
|
}
|
|
|
|
rc = cb_data->status;
|
|
out:
|
|
free(cb_data);
|
|
|
|
return rc;
|
|
}
|
|
|
|
/*
|
|
* fsync()
|
|
*/
|
|
static void fsync_cb(struct smb2_context *smb2, int status,
|
|
void *command_data, void *private_data)
|
|
{
|
|
struct sync_cb_data *cb_data = private_data;
|
|
|
|
if (cb_data->status == SMB2_STATUS_CANCELLED) {
|
|
free(cb_data);
|
|
return;
|
|
}
|
|
|
|
cb_data->is_finished = 1;
|
|
cb_data->status = status;
|
|
}
|
|
|
|
int smb2_fsync(struct smb2_context *smb2, struct smb2fh *fh)
|
|
{
|
|
struct sync_cb_data *cb_data;
|
|
int rc = 0;
|
|
|
|
cb_data = calloc(1, sizeof(struct sync_cb_data));
|
|
if (cb_data == NULL) {
|
|
smb2_set_error(smb2, "Failed to allocate sync_cb_data");
|
|
return -ENOMEM;
|
|
}
|
|
|
|
rc = smb2_fsync_async(smb2, fh, fsync_cb, cb_data);
|
|
if (rc < 0) {
|
|
goto out;
|
|
}
|
|
|
|
rc = wait_for_reply(smb2, cb_data);
|
|
if (rc < 0) {
|
|
cb_data->status = SMB2_STATUS_CANCELLED;
|
|
return rc;
|
|
}
|
|
|
|
rc = cb_data->status;
|
|
out:
|
|
free(cb_data);
|
|
|
|
return rc;
|
|
}
|
|
|
|
/*
|
|
* pread()
|
|
*/
|
|
static void generic_status_cb(struct smb2_context *smb2, int status,
|
|
void *command_data, void *private_data)
|
|
{
|
|
struct sync_cb_data *cb_data = private_data;
|
|
|
|
if (cb_data->status == SMB2_STATUS_CANCELLED) {
|
|
free(cb_data);
|
|
return;
|
|
}
|
|
|
|
cb_data->is_finished = 1;
|
|
cb_data->status = status;
|
|
}
|
|
|
|
int smb2_pread(struct smb2_context *smb2, struct smb2fh *fh,
|
|
uint8_t *buf, uint32_t count, uint64_t offset)
|
|
{
|
|
struct sync_cb_data *cb_data;
|
|
int rc = 0;
|
|
|
|
cb_data = calloc(1, sizeof(struct sync_cb_data));
|
|
if (cb_data == NULL) {
|
|
smb2_set_error(smb2, "Failed to allocate sync_cb_data");
|
|
return -ENOMEM;
|
|
}
|
|
|
|
rc = smb2_pread_async(smb2, fh, buf, count, offset,
|
|
generic_status_cb, cb_data);
|
|
if (rc < 0) {
|
|
goto out;
|
|
}
|
|
|
|
rc = wait_for_reply(smb2, cb_data);
|
|
if (rc < 0) {
|
|
cb_data->status = SMB2_STATUS_CANCELLED;
|
|
return rc;
|
|
}
|
|
|
|
rc = cb_data->status;
|
|
out:
|
|
free(cb_data);
|
|
|
|
return rc;
|
|
}
|
|
|
|
int smb2_pwrite(struct smb2_context *smb2, struct smb2fh *fh,
|
|
const uint8_t *buf, uint32_t count, uint64_t offset)
|
|
{
|
|
struct sync_cb_data *cb_data;
|
|
int rc = 0;
|
|
|
|
cb_data = calloc(1, sizeof(struct sync_cb_data));
|
|
if (cb_data == NULL) {
|
|
smb2_set_error(smb2, "Failed to allocate sync_cb_data");
|
|
return -ENOMEM;
|
|
}
|
|
|
|
rc = smb2_pwrite_async(smb2, fh, buf, count, offset,
|
|
generic_status_cb, cb_data);
|
|
if (rc < 0) {
|
|
goto out;
|
|
}
|
|
|
|
rc = wait_for_reply(smb2, cb_data);
|
|
if (rc < 0) {
|
|
cb_data->status = SMB2_STATUS_CANCELLED;
|
|
return rc;
|
|
}
|
|
|
|
rc = cb_data->status;
|
|
out:
|
|
free(cb_data);
|
|
|
|
return rc;
|
|
}
|
|
|
|
int smb2_read(struct smb2_context *smb2, struct smb2fh *fh,
|
|
uint8_t *buf, uint32_t count)
|
|
{
|
|
struct sync_cb_data *cb_data;
|
|
int rc = 0;
|
|
|
|
cb_data = calloc(1, sizeof(struct sync_cb_data));
|
|
if (cb_data == NULL) {
|
|
smb2_set_error(smb2, "Failed to allocate sync_cb_data");
|
|
return -ENOMEM;
|
|
}
|
|
|
|
rc = smb2_read_async(smb2, fh, buf, count,
|
|
generic_status_cb, cb_data);
|
|
if (rc < 0) {
|
|
goto out;
|
|
}
|
|
|
|
rc = wait_for_reply(smb2, cb_data);
|
|
if (rc < 0) {
|
|
cb_data->status = SMB2_STATUS_CANCELLED;
|
|
return rc;
|
|
}
|
|
|
|
rc = cb_data->status;
|
|
out:
|
|
free(cb_data);
|
|
|
|
return rc;
|
|
}
|
|
|
|
int smb2_write(struct smb2_context *smb2, struct smb2fh *fh,
|
|
const uint8_t *buf, uint32_t count)
|
|
{
|
|
struct sync_cb_data *cb_data;
|
|
int rc = 0;
|
|
|
|
cb_data = calloc(1, sizeof(struct sync_cb_data));
|
|
if (cb_data == NULL) {
|
|
smb2_set_error(smb2, "Failed to allocate sync_cb_data");
|
|
return -ENOMEM;
|
|
}
|
|
|
|
rc = smb2_write_async(smb2, fh, buf, count,
|
|
generic_status_cb, cb_data);
|
|
if (rc < 0) {
|
|
goto out;
|
|
}
|
|
|
|
rc = wait_for_reply(smb2, cb_data);
|
|
if (rc < 0) {
|
|
cb_data->status = SMB2_STATUS_CANCELLED;
|
|
return rc;
|
|
}
|
|
|
|
rc = cb_data->status;
|
|
out:
|
|
free(cb_data);
|
|
|
|
return rc;
|
|
}
|
|
|
|
int smb2_unlink(struct smb2_context *smb2, const char *path)
|
|
{
|
|
struct sync_cb_data *cb_data;
|
|
int rc = 0;
|
|
|
|
cb_data = calloc(1, sizeof(struct sync_cb_data));
|
|
if (cb_data == NULL) {
|
|
smb2_set_error(smb2, "Failed to allocate sync_cb_data");
|
|
return -ENOMEM;
|
|
}
|
|
|
|
rc = smb2_unlink_async(smb2, path,
|
|
generic_status_cb, cb_data);
|
|
if (rc < 0) {
|
|
goto out;
|
|
}
|
|
|
|
rc = wait_for_reply(smb2, cb_data);
|
|
if (rc < 0) {
|
|
cb_data->status = SMB2_STATUS_CANCELLED;
|
|
return rc;
|
|
}
|
|
|
|
rc = cb_data->status;
|
|
out:
|
|
free(cb_data);
|
|
|
|
return rc;
|
|
}
|
|
|
|
int smb2_rmdir(struct smb2_context *smb2, const char *path)
|
|
{
|
|
struct sync_cb_data *cb_data;
|
|
int rc = 0;
|
|
|
|
cb_data = calloc(1, sizeof(struct sync_cb_data));
|
|
if (cb_data == NULL) {
|
|
smb2_set_error(smb2, "Failed to allocate sync_cb_data");
|
|
return -ENOMEM;
|
|
}
|
|
|
|
rc = smb2_rmdir_async(smb2, path,
|
|
generic_status_cb, cb_data);
|
|
if (rc < 0) {
|
|
goto out;
|
|
}
|
|
|
|
rc = wait_for_reply(smb2, cb_data);
|
|
if (rc < 0) {
|
|
cb_data->status = SMB2_STATUS_CANCELLED;
|
|
return rc;
|
|
}
|
|
|
|
rc = cb_data->status;
|
|
out:
|
|
free(cb_data);
|
|
|
|
return rc;
|
|
}
|
|
|
|
int smb2_mkdir(struct smb2_context *smb2, const char *path)
|
|
{
|
|
struct sync_cb_data *cb_data;
|
|
int rc = 0;
|
|
|
|
cb_data = calloc(1, sizeof(struct sync_cb_data));
|
|
if (cb_data == NULL) {
|
|
smb2_set_error(smb2, "Failed to allocate sync_cb_data");
|
|
return -ENOMEM;
|
|
}
|
|
|
|
rc = smb2_mkdir_async(smb2, path,
|
|
generic_status_cb, cb_data);
|
|
if (rc < 0) {
|
|
goto out;
|
|
}
|
|
|
|
rc = wait_for_reply(smb2, cb_data);
|
|
if (rc < 0) {
|
|
cb_data->status = SMB2_STATUS_CANCELLED;
|
|
return rc;
|
|
}
|
|
|
|
rc = cb_data->status;
|
|
out:
|
|
free(cb_data);
|
|
|
|
return rc;
|
|
}
|
|
|
|
int smb2_fstat(struct smb2_context *smb2, struct smb2fh *fh,
|
|
struct smb2_stat_64 *st)
|
|
{
|
|
struct sync_cb_data *cb_data;
|
|
int rc = 0;
|
|
|
|
cb_data = calloc(1, sizeof(struct sync_cb_data));
|
|
if (cb_data == NULL) {
|
|
smb2_set_error(smb2, "Failed to allocate sync_cb_data");
|
|
return -ENOMEM;
|
|
}
|
|
|
|
rc = smb2_fstat_async(smb2, fh, st,
|
|
generic_status_cb, cb_data);
|
|
if (rc < 0) {
|
|
goto out;
|
|
}
|
|
|
|
rc = wait_for_reply(smb2, cb_data);
|
|
if (rc < 0) {
|
|
cb_data->status = SMB2_STATUS_CANCELLED;
|
|
return rc;
|
|
}
|
|
|
|
rc = cb_data->status;
|
|
out:
|
|
free(cb_data);
|
|
|
|
return rc;
|
|
}
|
|
|
|
int smb2_stat(struct smb2_context *smb2, const char *path,
|
|
struct smb2_stat_64 *st)
|
|
{
|
|
struct sync_cb_data *cb_data;
|
|
int rc = 0;
|
|
|
|
cb_data = calloc(1, sizeof(struct sync_cb_data));
|
|
if (cb_data == NULL) {
|
|
smb2_set_error(smb2, "Failed to allocate sync_cb_data");
|
|
return -ENOMEM;
|
|
}
|
|
|
|
rc = smb2_stat_async(smb2, path, st,
|
|
generic_status_cb, cb_data);
|
|
if (rc < 0) {
|
|
goto out;
|
|
}
|
|
|
|
rc = wait_for_reply(smb2, cb_data);
|
|
if (rc < 0) {
|
|
cb_data->status = SMB2_STATUS_CANCELLED;
|
|
return rc;
|
|
}
|
|
|
|
rc = cb_data->status;
|
|
out:
|
|
free(cb_data);
|
|
|
|
return rc;
|
|
}
|
|
|
|
int smb2_rename(struct smb2_context *smb2, const char *oldpath,
|
|
const char *newpath)
|
|
{
|
|
struct sync_cb_data *cb_data;
|
|
int rc = 0;
|
|
|
|
cb_data = calloc(1, sizeof(struct sync_cb_data));
|
|
if (cb_data == NULL) {
|
|
smb2_set_error(smb2, "Failed to allocate sync_cb_data");
|
|
return -ENOMEM;
|
|
}
|
|
|
|
rc = smb2_rename_async(smb2, oldpath, newpath,
|
|
generic_status_cb, cb_data);
|
|
if (rc < 0) {
|
|
goto out;
|
|
}
|
|
|
|
rc = wait_for_reply(smb2, cb_data);
|
|
if (rc < 0) {
|
|
cb_data->status = SMB2_STATUS_CANCELLED;
|
|
return rc;
|
|
}
|
|
|
|
rc = cb_data->status;
|
|
out:
|
|
free(cb_data);
|
|
|
|
return rc;
|
|
}
|
|
|
|
int smb2_statvfs(struct smb2_context *smb2, const char *path,
|
|
struct smb2_statvfs *st)
|
|
{
|
|
struct sync_cb_data *cb_data;
|
|
int rc = 0;
|
|
|
|
cb_data = calloc(1, sizeof(struct sync_cb_data));
|
|
if (cb_data == NULL) {
|
|
smb2_set_error(smb2, "Failed to allocate sync_cb_data");
|
|
return -ENOMEM;
|
|
}
|
|
|
|
rc = smb2_statvfs_async(smb2, path, st,
|
|
generic_status_cb, cb_data);
|
|
if (rc < 0) {
|
|
goto out;
|
|
}
|
|
|
|
rc = wait_for_reply(smb2, cb_data);
|
|
if (rc < 0) {
|
|
cb_data->status = SMB2_STATUS_CANCELLED;
|
|
return rc;
|
|
}
|
|
|
|
rc = cb_data->status;
|
|
out:
|
|
free(cb_data);
|
|
|
|
return rc;
|
|
}
|
|
|
|
int smb2_truncate(struct smb2_context *smb2, const char *path,
|
|
uint64_t length)
|
|
{
|
|
struct sync_cb_data *cb_data;
|
|
int rc = 0;
|
|
|
|
cb_data = calloc(1, sizeof(struct sync_cb_data));
|
|
if (cb_data == NULL) {
|
|
smb2_set_error(smb2, "Failed to allocate sync_cb_data");
|
|
return -ENOMEM;
|
|
}
|
|
|
|
rc = smb2_truncate_async(smb2, path, length,
|
|
generic_status_cb, cb_data);
|
|
if (rc < 0) {
|
|
goto out;
|
|
}
|
|
|
|
rc = wait_for_reply(smb2, cb_data);
|
|
if (rc < 0) {
|
|
cb_data->status = SMB2_STATUS_CANCELLED;
|
|
return rc;
|
|
}
|
|
|
|
rc = cb_data->status;
|
|
out:
|
|
free(cb_data);
|
|
|
|
return rc;
|
|
}
|
|
|
|
int smb2_ftruncate(struct smb2_context *smb2, struct smb2fh *fh,
|
|
uint64_t length)
|
|
{
|
|
struct sync_cb_data *cb_data;
|
|
int rc = 0;
|
|
|
|
cb_data = calloc(1, sizeof(struct sync_cb_data));
|
|
if (cb_data == NULL) {
|
|
smb2_set_error(smb2, "Failed to allocate sync_cb_data");
|
|
return -ENOMEM;
|
|
}
|
|
|
|
rc = smb2_ftruncate_async(smb2, fh, length,
|
|
generic_status_cb, cb_data);
|
|
if (rc < 0) {
|
|
goto out;
|
|
}
|
|
|
|
rc = wait_for_reply(smb2, cb_data);
|
|
if (rc < 0) {
|
|
cb_data->status = SMB2_STATUS_CANCELLED;
|
|
return rc;
|
|
}
|
|
|
|
rc = cb_data->status;
|
|
out:
|
|
free(cb_data);
|
|
|
|
return rc;
|
|
}
|
|
|
|
struct readlink_cb_data {
|
|
char *buf;
|
|
int len;
|
|
};
|
|
|
|
static void readlink_cb(struct smb2_context *smb2, int status,
|
|
void *command_data, void *private_data)
|
|
{
|
|
struct sync_cb_data *cb_data = private_data;
|
|
struct readlink_cb_data *rl_data = cb_data->ptr;
|
|
|
|
if (cb_data->status == SMB2_STATUS_CANCELLED) {
|
|
free(cb_data);
|
|
return;
|
|
}
|
|
|
|
cb_data->is_finished = 1;
|
|
cb_data->status = status;
|
|
strncpy(rl_data->buf, command_data, rl_data->len);
|
|
}
|
|
|
|
int smb2_readlink(struct smb2_context *smb2, const char *path,
|
|
char *buf, uint32_t len)
|
|
{
|
|
struct sync_cb_data *cb_data;
|
|
struct readlink_cb_data rl_data _U_;
|
|
int rc = 0;
|
|
|
|
cb_data = calloc(1, sizeof(struct sync_cb_data));
|
|
if (cb_data == NULL) {
|
|
smb2_set_error(smb2, "Failed to allocate sync_cb_data");
|
|
return -ENOMEM;
|
|
}
|
|
|
|
rl_data.buf = buf;
|
|
rl_data.len = len;
|
|
|
|
cb_data->ptr = &rl_data;
|
|
|
|
rc = smb2_readlink_async(smb2, path, readlink_cb, cb_data);
|
|
if (rc < 0) {
|
|
goto out;
|
|
}
|
|
|
|
rc = wait_for_reply(smb2, cb_data);
|
|
if (rc < 0) {
|
|
cb_data->status = SMB2_STATUS_CANCELLED;
|
|
return rc;
|
|
}
|
|
|
|
rc = cb_data->status;
|
|
out:
|
|
free(cb_data);
|
|
|
|
return rc;
|
|
}
|
|
|
|
static void echo_cb(struct smb2_context *smb2, int status,
|
|
void *command_data, void *private_data)
|
|
{
|
|
struct sync_cb_data *cb_data = private_data;
|
|
|
|
if (cb_data->status == SMB2_STATUS_CANCELLED) {
|
|
free(cb_data);
|
|
return;
|
|
}
|
|
|
|
cb_data->is_finished = 1;
|
|
cb_data->status = status;
|
|
}
|
|
|
|
/*
|
|
* Send SMB2_ECHO command to the server
|
|
*/
|
|
int smb2_echo(struct smb2_context *smb2)
|
|
{
|
|
struct sync_cb_data *cb_data;
|
|
int rc = 0;
|
|
|
|
if (!SMB2_VALID_SOCKET(smb2->fd)) {
|
|
smb2_set_error(smb2, "Not Connected to Server");
|
|
return -ENOMEM;
|
|
}
|
|
|
|
cb_data = calloc(1, sizeof(struct sync_cb_data));
|
|
if (cb_data == NULL) {
|
|
smb2_set_error(smb2, "Failed to allocate sync_cb_data");
|
|
return -ENOMEM;
|
|
}
|
|
|
|
rc = smb2_echo_async(smb2, echo_cb, cb_data);
|
|
if (rc < 0) {
|
|
goto out;
|
|
}
|
|
|
|
rc = wait_for_reply(smb2, cb_data);
|
|
if (rc < 0) {
|
|
cb_data->status = SMB2_STATUS_CANCELLED;
|
|
return rc;
|
|
}
|
|
|
|
rc = cb_data->status;
|
|
out:
|
|
free(cb_data);
|
|
|
|
return rc;
|
|
}
|
|
|
|
static void sync_notify_change_cb(struct smb2_context *smb2, int status,
|
|
void *command_data, void *private_data)
|
|
{
|
|
struct sync_cb_data *cb_data = private_data;
|
|
|
|
if (cb_data->status == SMB2_STATUS_CANCELLED) {
|
|
return;
|
|
}
|
|
|
|
cb_data->is_finished = 1;
|
|
cb_data->ptr = command_data;
|
|
}
|
|
|
|
|
|
/**
|
|
* One-off sync command for getting notify change response
|
|
*/
|
|
struct smb2_file_notify_change_information *smb2_notify_change(struct smb2_context *smb2, const char *path, uint16_t flags, uint32_t filter)
|
|
{
|
|
struct sync_cb_data *cb_data;
|
|
void *ptr;
|
|
|
|
cb_data = calloc(1, sizeof(struct sync_cb_data));
|
|
if (cb_data == NULL) {
|
|
smb2_set_error(smb2, "Failed to allocate sync_cb_data");
|
|
return NULL;
|
|
}
|
|
|
|
if (smb2_notify_change_async(smb2, path, flags, filter, 0,
|
|
sync_notify_change_cb, cb_data) != 0) {
|
|
smb2_set_error(smb2, "smb2_notify_change failed");
|
|
free(cb_data);
|
|
return NULL;
|
|
}
|
|
|
|
if (wait_for_reply(smb2, cb_data) < 0) {
|
|
cb_data->status = SMB2_STATUS_CANCELLED;
|
|
free(cb_data);
|
|
return NULL;
|
|
}
|
|
|
|
ptr = cb_data->ptr;
|
|
free(cb_data);
|
|
return ptr;
|
|
}
|