FFmpeg
libsmbclient.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2014 Lukasz Marek <lukasz.m.luki@gmail.com>
3  *
4  * This file is part of FFmpeg.
5  *
6  * FFmpeg is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * FFmpeg is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with FFmpeg; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19  */
20 
21 #include <libsmbclient.h>
22 #include "libavutil/avstring.h"
23 #include "libavutil/opt.h"
24 #include "url.h"
25 
26 typedef struct {
27  const AVClass *class;
28  SMBCCTX *ctx;
29  int dh;
30  int fd;
31  int64_t filesize;
32  int trunc;
33  int timeout;
34  char *workgroup;
36 
37 static void libsmbc_get_auth_data(SMBCCTX *c, const char *server, const char *share,
38  char *workgroup, int workgroup_len,
39  char *username, int username_len,
40  char *password, int password_len)
41 {
42  /* Do nothing yet. Credentials are passed via url.
43  * Callback must exists, there might be a segmentation fault otherwise. */
44 }
45 
47 {
48  LIBSMBContext *libsmbc = h->priv_data;
49 
50  libsmbc->ctx = smbc_new_context();
51  if (!libsmbc->ctx) {
52  int ret = AVERROR(errno);
53  av_log(h, AV_LOG_ERROR, "Cannot create context: %s.\n", strerror(errno));
54  return ret;
55  }
56  if (!smbc_init_context(libsmbc->ctx)) {
57  int ret = AVERROR(errno);
58  av_log(h, AV_LOG_ERROR, "Cannot initialize context: %s.\n", strerror(errno));
59  return ret;
60  }
61  smbc_set_context(libsmbc->ctx);
62 
63  smbc_setOptionUserData(libsmbc->ctx, h);
64  smbc_setFunctionAuthDataWithContext(libsmbc->ctx, libsmbc_get_auth_data);
65 
66  if (libsmbc->timeout != -1)
67  smbc_setTimeout(libsmbc->ctx, libsmbc->timeout);
68  if (libsmbc->workgroup)
69  smbc_setWorkgroup(libsmbc->ctx, libsmbc->workgroup);
70 
71  if (smbc_init(NULL, 0) < 0) {
72  int ret = AVERROR(errno);
73  av_log(h, AV_LOG_ERROR, "Initialization failed: %s\n", strerror(errno));
74  return ret;
75  }
76  return 0;
77 }
78 
80 {
81  LIBSMBContext *libsmbc = h->priv_data;
82  if (libsmbc->fd >= 0) {
83  smbc_close(libsmbc->fd);
84  libsmbc->fd = -1;
85  }
86  if (libsmbc->ctx) {
87  smbc_free_context(libsmbc->ctx, 1);
88  libsmbc->ctx = NULL;
89  }
90  return 0;
91 }
92 
93 static av_cold int libsmbc_open(URLContext *h, const char *url, int flags)
94 {
95  LIBSMBContext *libsmbc = h->priv_data;
96  int access, ret;
97  struct stat st;
98 
99  libsmbc->fd = -1;
100  libsmbc->filesize = -1;
101 
102  if ((ret = libsmbc_connect(h)) < 0)
103  goto fail;
104 
105  if ((flags & AVIO_FLAG_WRITE) && (flags & AVIO_FLAG_READ)) {
106  access = O_CREAT | O_RDWR;
107  if (libsmbc->trunc)
108  access |= O_TRUNC;
109  } else if (flags & AVIO_FLAG_WRITE) {
110  access = O_CREAT | O_WRONLY;
111  if (libsmbc->trunc)
112  access |= O_TRUNC;
113  } else
114  access = O_RDONLY;
115 
116  /* 0666 = -rw-rw-rw- = read+write for everyone, minus umask */
117  if ((libsmbc->fd = smbc_open(url, access, 0666)) < 0) {
118  ret = AVERROR(errno);
119  av_log(h, AV_LOG_ERROR, "File open failed: %s\n", strerror(errno));
120  goto fail;
121  }
122 
123  if (smbc_fstat(libsmbc->fd, &st) < 0)
124  av_log(h, AV_LOG_WARNING, "Cannot stat file: %s\n", strerror(errno));
125  else
126  libsmbc->filesize = st.st_size;
127 
128  return 0;
129  fail:
130  libsmbc_close(h);
131  return ret;
132 }
133 
134 static int64_t libsmbc_seek(URLContext *h, int64_t pos, int whence)
135 {
136  LIBSMBContext *libsmbc = h->priv_data;
137  int64_t newpos;
138 
139  if (whence == AVSEEK_SIZE) {
140  if (libsmbc->filesize == -1) {
141  av_log(h, AV_LOG_ERROR, "Error during seeking: filesize is unknown.\n");
142  return AVERROR(EIO);
143  } else
144  return libsmbc->filesize;
145  }
146 
147  if ((newpos = smbc_lseek(libsmbc->fd, pos, whence)) < 0) {
148  int err = errno;
149  av_log(h, AV_LOG_ERROR, "Error during seeking: %s\n", strerror(err));
150  return AVERROR(err);
151  }
152 
153  return newpos;
154 }
155 
156 static int libsmbc_read(URLContext *h, unsigned char *buf, int size)
157 {
158  LIBSMBContext *libsmbc = h->priv_data;
159  int bytes_read;
160 
161  if ((bytes_read = smbc_read(libsmbc->fd, buf, size)) < 0) {
162  int ret = AVERROR(errno);
163  av_log(h, AV_LOG_ERROR, "Read error: %s\n", strerror(errno));
164  return ret;
165  }
166 
167  return bytes_read ? bytes_read : AVERROR_EOF;
168 }
169 
170 static int libsmbc_write(URLContext *h, const unsigned char *buf, int size)
171 {
172  LIBSMBContext *libsmbc = h->priv_data;
173  int bytes_written;
174 
175  if ((bytes_written = smbc_write(libsmbc->fd, buf, size)) < 0) {
176  int ret = AVERROR(errno);
177  av_log(h, AV_LOG_ERROR, "Write error: %s\n", strerror(errno));
178  return ret;
179  }
180 
181  return bytes_written;
182 }
183 
185 {
186  LIBSMBContext *libsmbc = h->priv_data;
187  int ret;
188 
189  if ((ret = libsmbc_connect(h)) < 0)
190  goto fail;
191 
192  if ((libsmbc->dh = smbc_opendir(h->filename)) < 0) {
193  ret = AVERROR(errno);
194  av_log(h, AV_LOG_ERROR, "Error opening dir: %s\n", strerror(errno));
195  goto fail;
196  }
197 
198  return 0;
199 
200  fail:
201  libsmbc_close(h);
202  return ret;
203 }
204 
206 {
207  LIBSMBContext *libsmbc = h->priv_data;
209  struct smbc_dirent *dirent = NULL;
210  char *url = NULL;
211  int skip_entry;
212 
213  *next = entry = ff_alloc_dir_entry();
214  if (!entry)
215  return AVERROR(ENOMEM);
216 
217  do {
218  skip_entry = 0;
219  dirent = smbc_readdir(libsmbc->dh);
220  if (!dirent) {
221  av_freep(next);
222  return 0;
223  }
224  switch (dirent->smbc_type) {
225  case SMBC_DIR:
226  entry->type = AVIO_ENTRY_DIRECTORY;
227  break;
228  case SMBC_FILE:
229  entry->type = AVIO_ENTRY_FILE;
230  break;
231  case SMBC_FILE_SHARE:
232  entry->type = AVIO_ENTRY_SHARE;
233  break;
234  case SMBC_SERVER:
235  entry->type = AVIO_ENTRY_SERVER;
236  break;
237  case SMBC_WORKGROUP:
238  entry->type = AVIO_ENTRY_WORKGROUP;
239  break;
240  case SMBC_COMMS_SHARE:
241  case SMBC_IPC_SHARE:
242  case SMBC_PRINTER_SHARE:
243  skip_entry = 1;
244  break;
245  case SMBC_LINK:
246  default:
247  entry->type = AVIO_ENTRY_UNKNOWN;
248  break;
249  }
250  } while (skip_entry || !strcmp(dirent->name, ".") ||
251  !strcmp(dirent->name, ".."));
252 
253  entry->name = av_strdup(dirent->name);
254  if (!entry->name) {
255  av_freep(next);
256  return AVERROR(ENOMEM);
257  }
258 
259  url = av_append_path_component(h->filename, dirent->name);
260  if (url) {
261  struct stat st;
262  if (!smbc_stat(url, &st)) {
263  entry->group_id = st.st_gid;
264  entry->user_id = st.st_uid;
265  entry->size = st.st_size;
266  entry->filemode = st.st_mode & 0777;
267  entry->modification_timestamp = INT64_C(1000000) * st.st_mtime;
268  entry->access_timestamp = INT64_C(1000000) * st.st_atime;
269  entry->status_change_timestamp = INT64_C(1000000) * st.st_ctime;
270  }
271  av_free(url);
272  }
273 
274  return 0;
275 }
276 
278 {
279  LIBSMBContext *libsmbc = h->priv_data;
280  if (libsmbc->dh >= 0) {
281  smbc_closedir(libsmbc->dh);
282  libsmbc->dh = -1;
283  }
284  libsmbc_close(h);
285  return 0;
286 }
287 
289 {
290  LIBSMBContext *libsmbc = h->priv_data;
291  int ret;
292  struct stat st;
293 
294  if ((ret = libsmbc_connect(h)) < 0)
295  goto cleanup;
296 
297  if ((libsmbc->fd = smbc_open(h->filename, O_WRONLY, 0666)) < 0) {
298  ret = AVERROR(errno);
299  goto cleanup;
300  }
301 
302  if (smbc_fstat(libsmbc->fd, &st) < 0) {
303  ret = AVERROR(errno);
304  goto cleanup;
305  }
306 
307  smbc_close(libsmbc->fd);
308  libsmbc->fd = -1;
309 
310  if (S_ISDIR(st.st_mode)) {
311  if (smbc_rmdir(h->filename) < 0) {
312  ret = AVERROR(errno);
313  goto cleanup;
314  }
315  } else {
316  if (smbc_unlink(h->filename) < 0) {
317  ret = AVERROR(errno);
318  goto cleanup;
319  }
320  }
321 
322  ret = 0;
323 
324 cleanup:
325  libsmbc_close(h);
326  return ret;
327 }
328 
329 static int libsmbc_move(URLContext *h_src, URLContext *h_dst)
330 {
331  LIBSMBContext *libsmbc = h_src->priv_data;
332  int ret;
333 
334  if ((ret = libsmbc_connect(h_src)) < 0)
335  goto cleanup;
336 
337  if ((libsmbc->dh = smbc_rename(h_src->filename, h_dst->filename)) < 0) {
338  ret = AVERROR(errno);
339  goto cleanup;
340  }
341 
342  ret = 0;
343 
344 cleanup:
345  libsmbc_close(h_src);
346  return ret;
347 }
348 
349 #define OFFSET(x) offsetof(LIBSMBContext, x)
350 #define D AV_OPT_FLAG_DECODING_PARAM
351 #define E AV_OPT_FLAG_ENCODING_PARAM
352 static const AVOption options[] = {
353  {"timeout", "set timeout in ms of socket I/O operations", OFFSET(timeout), AV_OPT_TYPE_INT, {.i64 = -1}, -1, INT_MAX, D|E },
354  {"truncate", "truncate existing files on write", OFFSET(trunc), AV_OPT_TYPE_INT, { .i64 = 1 }, 0, 1, E },
355  {"workgroup", "set the workgroup used for making connections", OFFSET(workgroup), AV_OPT_TYPE_STRING, { 0 }, 0, 0, D|E },
356  {NULL}
357 };
358 
360  .class_name = "libsmbc",
361  .item_name = av_default_item_name,
362  .option = options,
363  .version = LIBAVUTIL_VERSION_INT,
364 };
365 
367  .name = "smb",
368  .url_open = libsmbc_open,
369  .url_read = libsmbc_read,
370  .url_write = libsmbc_write,
371  .url_seek = libsmbc_seek,
372  .url_close = libsmbc_close,
373  .url_delete = libsmbc_delete,
374  .url_move = libsmbc_move,
375  .url_open_dir = libsmbc_open_dir,
376  .url_read_dir = libsmbc_read_dir,
377  .url_close_dir = libsmbc_close_dir,
378  .priv_data_size = sizeof(LIBSMBContext),
379  .priv_data_class = &libsmbclient_context_class,
381 };
AV_LOG_WARNING
#define AV_LOG_WARNING
Something somehow does not look correct.
Definition: log.h:186
entry
#define entry
Definition: aom_film_grain_template.c:66
AVERROR
Filter the word “frame” indicates either a video frame or a group of audio as stored in an AVFrame structure Format for each input and each output the list of supported formats For video that means pixel format For audio that means channel sample they are references to shared objects When the negotiation mechanism computes the intersection of the formats supported at each end of a all references to both lists are replaced with a reference to the intersection And when a single format is eventually chosen for a link amongst the remaining all references to the list are updated That means that if a filter requires that its input and output have the same format amongst a supported all it has to do is use a reference to the same list of formats query_formats can leave some formats unset and return AVERROR(EAGAIN) to cause the negotiation mechanism toagain later. That can be used by filters with complex requirements to use the format negotiated on one link to set the formats supported on another. Frame references ownership and permissions
opt.h
libsmbc_seek
static int64_t libsmbc_seek(URLContext *h, int64_t pos, int whence)
Definition: libsmbclient.c:134
URLContext::filename
char * filename
specified URL
Definition: url.h:39
URL_PROTOCOL_FLAG_NETWORK
#define URL_PROTOCOL_FLAG_NETWORK
Definition: url.h:33
AVERROR_EOF
#define AVERROR_EOF
End of file.
Definition: error.h:57
options
static const AVOption options[]
Definition: libsmbclient.c:352
cleanup
static av_cold void cleanup(FlashSV2Context *s)
Definition: flashsv2enc.c:130
AVOption
AVOption.
Definition: opt.h:346
AVSEEK_SIZE
#define AVSEEK_SIZE
ORing this as the "whence" parameter to a seek function causes it to return the filesize without seek...
Definition: avio.h:468
LIBSMBContext::trunc
int trunc
Definition: libsmbclient.c:32
LIBSMBContext::dh
int dh
Definition: libsmbclient.c:29
URLProtocol
Definition: url.h:51
AVIO_ENTRY_UNKNOWN
@ AVIO_ENTRY_UNKNOWN
Definition: avio.h:68
av_append_path_component
char * av_append_path_component(const char *path, const char *component)
Append path component to the existing path.
Definition: avstring.c:296
AVIO_ENTRY_DIRECTORY
@ AVIO_ENTRY_DIRECTORY
Definition: avio.h:71
LIBSMBContext::ctx
SMBCCTX * ctx
Definition: libsmbclient.c:28
libsmbc_delete
static int libsmbc_delete(URLContext *h)
Definition: libsmbclient.c:288
fail
#define fail()
Definition: checkasm.h:179
LIBSMBContext::workgroup
char * workgroup
Definition: libsmbclient.c:34
trunc
static __device__ float trunc(float a)
Definition: cuda_runtime.h:179
LIBSMBContext::timeout
int timeout
Definition: libsmbclient.c:33
URLContext::priv_data
void * priv_data
Definition: url.h:38
AV_LOG_ERROR
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:180
av_cold
#define av_cold
Definition: attributes.h:90
libsmbc_close
static av_cold int libsmbc_close(URLContext *h)
Definition: libsmbclient.c:79
LIBSMBContext::fd
int fd
Definition: libsmbclient.c:30
AVIO_FLAG_WRITE
#define AVIO_FLAG_WRITE
write-only
Definition: avio.h:618
D
#define D
Definition: libsmbclient.c:350
libsmbc_open
static av_cold int libsmbc_open(URLContext *h, const char *url, int flags)
Definition: libsmbclient.c:93
LIBAVUTIL_VERSION_INT
#define LIBAVUTIL_VERSION_INT
Definition: version.h:85
AVClass
Describe the class of an AVClass context structure.
Definition: log.h:66
NULL
#define NULL
Definition: coverity.c:32
ff_libsmbclient_protocol
const URLProtocol ff_libsmbclient_protocol
Definition: libsmbclient.c:366
av_default_item_name
const char * av_default_item_name(void *ptr)
Return the context name.
Definition: log.c:237
AVIO_ENTRY_FILE
@ AVIO_ENTRY_FILE
Definition: avio.h:75
libsmbc_get_auth_data
static void libsmbc_get_auth_data(SMBCCTX *c, const char *server, const char *share, char *workgroup, int workgroup_len, char *username, int username_len, char *password, int password_len)
Definition: libsmbclient.c:37
c
Undefined Behavior In the C some operations are like signed integer dereferencing freed accessing outside allocated Undefined Behavior must not occur in a C it is not safe even if the output of undefined operations is unused The unsafety may seem nit picking but Optimizing compilers have in fact optimized code on the assumption that no undefined Behavior occurs Optimizing code based on wrong assumptions can and has in some cases lead to effects beyond the output of computations The signed integer overflow problem in speed critical code Code which is highly optimized and works with signed integers sometimes has the problem that often the output of the computation does not c
Definition: undefined.txt:32
size
int size
Definition: twinvq_data.h:10344
AVIODirEntry
Describes single entry of the directory.
Definition: avio.h:87
libsmbc_open_dir
static int libsmbc_open_dir(URLContext *h)
Definition: libsmbclient.c:184
URLProtocol::name
const char * name
Definition: url.h:52
libsmbc_close_dir
static int libsmbc_close_dir(URLContext *h)
Definition: libsmbclient.c:277
libsmbclient_context_class
static const AVClass libsmbclient_context_class
Definition: libsmbclient.c:359
OFFSET
#define OFFSET(x)
Definition: libsmbclient.c:349
ff_alloc_dir_entry
AVIODirEntry * ff_alloc_dir_entry(void)
Allocate directory entry with default values.
Definition: url.c:327
URLContext
Definition: url.h:35
libsmbc_move
static int libsmbc_move(URLContext *h_src, URLContext *h_dst)
Definition: libsmbclient.c:329
libsmbc_read_dir
static int libsmbc_read_dir(URLContext *h, AVIODirEntry **next)
Definition: libsmbclient.c:205
url.h
ret
ret
Definition: filter_design.txt:187
AVClass::class_name
const char * class_name
The name of the class; usually it is the same name as the context structure type to which the AVClass...
Definition: log.h:71
pos
unsigned int pos
Definition: spdifenc.c:413
AV_OPT_TYPE_INT
@ AV_OPT_TYPE_INT
Definition: opt.h:235
LIBSMBContext::filesize
int64_t filesize
Definition: libsmbclient.c:31
E
#define E
Definition: libsmbclient.c:351
AVIO_ENTRY_WORKGROUP
@ AVIO_ENTRY_WORKGROUP
Definition: avio.h:78
AVIO_FLAG_READ
#define AVIO_FLAG_READ
read-only
Definition: avio.h:617
av_strdup
char * av_strdup(const char *s)
Duplicate a string.
Definition: mem.c:270
av_free
#define av_free(p)
Definition: tableprint_vlc.h:33
libsmbc_connect
static av_cold int libsmbc_connect(URLContext *h)
Definition: libsmbclient.c:46
av_freep
#define av_freep(p)
Definition: tableprint_vlc.h:34
AVIO_ENTRY_SERVER
@ AVIO_ENTRY_SERVER
Definition: avio.h:76
libsmbc_read
static int libsmbc_read(URLContext *h, unsigned char *buf, int size)
Definition: libsmbclient.c:156
LIBSMBContext
Definition: libsmbclient.c:26
flags
#define flags(name, subs,...)
Definition: cbs_av1.c:474
av_log
#define av_log(a,...)
Definition: tableprint_vlc.h:27
h
h
Definition: vp9dsp_template.c:2038
avstring.h
AV_OPT_TYPE_STRING
@ AV_OPT_TYPE_STRING
Definition: opt.h:239
libsmbc_write
static int libsmbc_write(URLContext *h, const unsigned char *buf, int size)
Definition: libsmbclient.c:170
AVIO_ENTRY_SHARE
@ AVIO_ENTRY_SHARE
Definition: avio.h:77