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/mem.h"
24 #include "libavutil/opt.h"
25 #include "url.h"
26 
27 typedef struct {
28  const AVClass *class;
29  SMBCCTX *ctx;
30  int dh;
31  int fd;
32  int64_t filesize;
33  int trunc;
34  int timeout;
35  char *workgroup;
37 
38 static void libsmbc_get_auth_data(SMBCCTX *c, const char *server, const char *share,
39  char *workgroup, int workgroup_len,
40  char *username, int username_len,
41  char *password, int password_len)
42 {
43  /* Do nothing yet. Credentials are passed via url.
44  * Callback must exists, there might be a segmentation fault otherwise. */
45 }
46 
48 {
49  LIBSMBContext *libsmbc = h->priv_data;
50 
51  libsmbc->ctx = smbc_new_context();
52  if (!libsmbc->ctx) {
53  int ret = AVERROR(errno);
54  av_log(h, AV_LOG_ERROR, "Cannot create context: %s.\n", strerror(errno));
55  return ret;
56  }
57  if (!smbc_init_context(libsmbc->ctx)) {
58  int ret = AVERROR(errno);
59  av_log(h, AV_LOG_ERROR, "Cannot initialize context: %s.\n", strerror(errno));
60  return ret;
61  }
62  smbc_set_context(libsmbc->ctx);
63 
64  smbc_setOptionUserData(libsmbc->ctx, h);
65  smbc_setFunctionAuthDataWithContext(libsmbc->ctx, libsmbc_get_auth_data);
66 
67  if (libsmbc->timeout != -1)
68  smbc_setTimeout(libsmbc->ctx, libsmbc->timeout);
69  if (libsmbc->workgroup)
70  smbc_setWorkgroup(libsmbc->ctx, libsmbc->workgroup);
71 
72  if (smbc_init(NULL, 0) < 0) {
73  int ret = AVERROR(errno);
74  av_log(h, AV_LOG_ERROR, "Initialization failed: %s\n", strerror(errno));
75  return ret;
76  }
77  return 0;
78 }
79 
81 {
82  LIBSMBContext *libsmbc = h->priv_data;
83  if (libsmbc->fd >= 0) {
84  smbc_close(libsmbc->fd);
85  libsmbc->fd = -1;
86  }
87  if (libsmbc->ctx) {
88  smbc_free_context(libsmbc->ctx, 1);
89  libsmbc->ctx = NULL;
90  }
91  return 0;
92 }
93 
94 static av_cold int libsmbc_open(URLContext *h, const char *url, int flags)
95 {
96  LIBSMBContext *libsmbc = h->priv_data;
97  int access, ret;
98  struct stat st;
99 
100  libsmbc->fd = -1;
101  libsmbc->filesize = -1;
102 
103  if ((ret = libsmbc_connect(h)) < 0)
104  goto fail;
105 
106  if ((flags & AVIO_FLAG_WRITE) && (flags & AVIO_FLAG_READ)) {
107  access = O_CREAT | O_RDWR;
108  if (libsmbc->trunc)
109  access |= O_TRUNC;
110  } else if (flags & AVIO_FLAG_WRITE) {
111  access = O_CREAT | O_WRONLY;
112  if (libsmbc->trunc)
113  access |= O_TRUNC;
114  } else
115  access = O_RDONLY;
116 
117  /* 0666 = -rw-rw-rw- = read+write for everyone, minus umask */
118  if ((libsmbc->fd = smbc_open(url, access, 0666)) < 0) {
119  ret = AVERROR(errno);
120  av_log(h, AV_LOG_ERROR, "File open failed: %s\n", strerror(errno));
121  goto fail;
122  }
123 
124  if (smbc_fstat(libsmbc->fd, &st) < 0)
125  av_log(h, AV_LOG_WARNING, "Cannot stat file: %s\n", strerror(errno));
126  else
127  libsmbc->filesize = st.st_size;
128 
129  return 0;
130  fail:
131  libsmbc_close(h);
132  return ret;
133 }
134 
135 static int64_t libsmbc_seek(URLContext *h, int64_t pos, int whence)
136 {
137  LIBSMBContext *libsmbc = h->priv_data;
138  int64_t newpos;
139 
140  if (whence == AVSEEK_SIZE) {
141  if (libsmbc->filesize == -1) {
142  av_log(h, AV_LOG_ERROR, "Error during seeking: filesize is unknown.\n");
143  return AVERROR(EIO);
144  } else
145  return libsmbc->filesize;
146  }
147 
148  if ((newpos = smbc_lseek(libsmbc->fd, pos, whence)) < 0) {
149  int err = errno;
150  av_log(h, AV_LOG_ERROR, "Error during seeking: %s\n", strerror(err));
151  return AVERROR(err);
152  }
153 
154  return newpos;
155 }
156 
157 static int libsmbc_read(URLContext *h, unsigned char *buf, int size)
158 {
159  LIBSMBContext *libsmbc = h->priv_data;
160  int bytes_read;
161 
162  if ((bytes_read = smbc_read(libsmbc->fd, buf, size)) < 0) {
163  int ret = AVERROR(errno);
164  av_log(h, AV_LOG_ERROR, "Read error: %s\n", strerror(errno));
165  return ret;
166  }
167 
168  return bytes_read ? bytes_read : AVERROR_EOF;
169 }
170 
171 static int libsmbc_write(URLContext *h, const unsigned char *buf, int size)
172 {
173  LIBSMBContext *libsmbc = h->priv_data;
174  int bytes_written;
175 
176  if ((bytes_written = smbc_write(libsmbc->fd, buf, size)) < 0) {
177  int ret = AVERROR(errno);
178  av_log(h, AV_LOG_ERROR, "Write error: %s\n", strerror(errno));
179  return ret;
180  }
181 
182  return bytes_written;
183 }
184 
186 {
187  LIBSMBContext *libsmbc = h->priv_data;
188  int ret;
189 
190  if ((ret = libsmbc_connect(h)) < 0)
191  goto fail;
192 
193  if ((libsmbc->dh = smbc_opendir(h->filename)) < 0) {
194  ret = AVERROR(errno);
195  av_log(h, AV_LOG_ERROR, "Error opening dir: %s\n", strerror(errno));
196  goto fail;
197  }
198 
199  return 0;
200 
201  fail:
202  libsmbc_close(h);
203  return ret;
204 }
205 
207 {
208  LIBSMBContext *libsmbc = h->priv_data;
210  struct smbc_dirent *dirent = NULL;
211  char *url = NULL;
212  int skip_entry;
213 
214  *next = entry = ff_alloc_dir_entry();
215  if (!entry)
216  return AVERROR(ENOMEM);
217 
218  do {
219  skip_entry = 0;
220  dirent = smbc_readdir(libsmbc->dh);
221  if (!dirent) {
222  av_freep(next);
223  return 0;
224  }
225  switch (dirent->smbc_type) {
226  case SMBC_DIR:
227  entry->type = AVIO_ENTRY_DIRECTORY;
228  break;
229  case SMBC_FILE:
230  entry->type = AVIO_ENTRY_FILE;
231  break;
232  case SMBC_FILE_SHARE:
233  entry->type = AVIO_ENTRY_SHARE;
234  break;
235  case SMBC_SERVER:
236  entry->type = AVIO_ENTRY_SERVER;
237  break;
238  case SMBC_WORKGROUP:
239  entry->type = AVIO_ENTRY_WORKGROUP;
240  break;
241  case SMBC_COMMS_SHARE:
242  case SMBC_IPC_SHARE:
243  case SMBC_PRINTER_SHARE:
244  skip_entry = 1;
245  break;
246  case SMBC_LINK:
247  default:
248  entry->type = AVIO_ENTRY_UNKNOWN;
249  break;
250  }
251  } while (skip_entry || !strcmp(dirent->name, ".") ||
252  !strcmp(dirent->name, ".."));
253 
254  entry->name = av_strdup(dirent->name);
255  if (!entry->name) {
256  av_freep(next);
257  return AVERROR(ENOMEM);
258  }
259 
260  url = av_append_path_component(h->filename, dirent->name);
261  if (url) {
262  struct stat st;
263  if (!smbc_stat(url, &st)) {
264  entry->group_id = st.st_gid;
265  entry->user_id = st.st_uid;
266  entry->size = st.st_size;
267  entry->filemode = st.st_mode & 0777;
268  entry->modification_timestamp = INT64_C(1000000) * st.st_mtime;
269  entry->access_timestamp = INT64_C(1000000) * st.st_atime;
270  entry->status_change_timestamp = INT64_C(1000000) * st.st_ctime;
271  }
272  av_free(url);
273  }
274 
275  return 0;
276 }
277 
279 {
280  LIBSMBContext *libsmbc = h->priv_data;
281  if (libsmbc->dh >= 0) {
282  smbc_closedir(libsmbc->dh);
283  libsmbc->dh = -1;
284  }
285  libsmbc_close(h);
286  return 0;
287 }
288 
290 {
291  LIBSMBContext *libsmbc = h->priv_data;
292  int ret;
293  struct stat st;
294 
295  if ((ret = libsmbc_connect(h)) < 0)
296  goto cleanup;
297 
298  if ((libsmbc->fd = smbc_open(h->filename, O_WRONLY, 0666)) < 0) {
299  ret = AVERROR(errno);
300  goto cleanup;
301  }
302 
303  if (smbc_fstat(libsmbc->fd, &st) < 0) {
304  ret = AVERROR(errno);
305  goto cleanup;
306  }
307 
308  smbc_close(libsmbc->fd);
309  libsmbc->fd = -1;
310 
311  if (S_ISDIR(st.st_mode)) {
312  if (smbc_rmdir(h->filename) < 0) {
313  ret = AVERROR(errno);
314  goto cleanup;
315  }
316  } else {
317  if (smbc_unlink(h->filename) < 0) {
318  ret = AVERROR(errno);
319  goto cleanup;
320  }
321  }
322 
323  ret = 0;
324 
325 cleanup:
326  libsmbc_close(h);
327  return ret;
328 }
329 
330 static int libsmbc_move(URLContext *h_src, URLContext *h_dst)
331 {
332  LIBSMBContext *libsmbc = h_src->priv_data;
333  int ret;
334 
335  if ((ret = libsmbc_connect(h_src)) < 0)
336  goto cleanup;
337 
338  if ((libsmbc->dh = smbc_rename(h_src->filename, h_dst->filename)) < 0) {
339  ret = AVERROR(errno);
340  goto cleanup;
341  }
342 
343  ret = 0;
344 
345 cleanup:
346  libsmbc_close(h_src);
347  return ret;
348 }
349 
350 #define OFFSET(x) offsetof(LIBSMBContext, x)
351 #define D AV_OPT_FLAG_DECODING_PARAM
352 #define E AV_OPT_FLAG_ENCODING_PARAM
353 static const AVOption options[] = {
354  {"timeout", "set timeout in ms of socket I/O operations", OFFSET(timeout), AV_OPT_TYPE_INT, {.i64 = -1}, -1, INT_MAX, D|E },
355  {"truncate", "truncate existing files on write", OFFSET(trunc), AV_OPT_TYPE_INT, { .i64 = 1 }, 0, 1, E },
356  {"workgroup", "set the workgroup used for making connections", OFFSET(workgroup), AV_OPT_TYPE_STRING, { 0 }, 0, 0, D|E },
357  {NULL}
358 };
359 
361  .class_name = "libsmbc",
362  .item_name = av_default_item_name,
363  .option = options,
364  .version = LIBAVUTIL_VERSION_INT,
365 };
366 
368  .name = "smb",
369  .url_open = libsmbc_open,
370  .url_read = libsmbc_read,
371  .url_write = libsmbc_write,
372  .url_seek = libsmbc_seek,
373  .url_close = libsmbc_close,
374  .url_delete = libsmbc_delete,
375  .url_move = libsmbc_move,
376  .url_open_dir = libsmbc_open_dir,
377  .url_read_dir = libsmbc_read_dir,
378  .url_close_dir = libsmbc_close_dir,
379  .priv_data_size = sizeof(LIBSMBContext),
380  .priv_data_class = &libsmbclient_context_class,
382 };
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:135
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:353
cleanup
static av_cold void cleanup(FlashSV2Context *s)
Definition: flashsv2enc.c:130
AVOption
AVOption.
Definition: opt.h:357
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:33
LIBSMBContext::dh
int dh
Definition: libsmbclient.c:30
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:29
libsmbc_delete
static int libsmbc_delete(URLContext *h)
Definition: libsmbclient.c:289
fail
#define fail()
Definition: checkasm.h:185
LIBSMBContext::workgroup
char * workgroup
Definition: libsmbclient.c:35
trunc
static __device__ float trunc(float a)
Definition: cuda_runtime.h:179
LIBSMBContext::timeout
int timeout
Definition: libsmbclient.c:34
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:80
LIBSMBContext::fd
int fd
Definition: libsmbclient.c:31
AVIO_FLAG_WRITE
#define AVIO_FLAG_WRITE
write-only
Definition: avio.h:618
D
#define D
Definition: libsmbclient.c:351
libsmbc_open
static av_cold int libsmbc_open(URLContext *h, const char *url, int flags)
Definition: libsmbclient.c:94
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:367
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:38
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:185
URLProtocol::name
const char * name
Definition: url.h:52
libsmbc_close_dir
static int libsmbc_close_dir(URLContext *h)
Definition: libsmbclient.c:278
libsmbclient_context_class
static const AVClass libsmbclient_context_class
Definition: libsmbclient.c:360
OFFSET
#define OFFSET(x)
Definition: libsmbclient.c:350
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:330
libsmbc_read_dir
static int libsmbc_read_dir(URLContext *h, AVIODirEntry **next)
Definition: libsmbclient.c:206
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:414
AV_OPT_TYPE_INT
@ AV_OPT_TYPE_INT
Definition: opt.h:245
LIBSMBContext::filesize
int64_t filesize
Definition: libsmbclient.c:32
E
#define E
Definition: libsmbclient.c:352
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:272
mem.h
av_free
#define av_free(p)
Definition: tableprint_vlc.h:33
libsmbc_connect
static av_cold int libsmbc_connect(URLContext *h)
Definition: libsmbclient.c:47
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:157
LIBSMBContext
Definition: libsmbclient.c:27
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:249
libsmbc_write
static int libsmbc_write(URLContext *h, const unsigned char *buf, int size)
Definition: libsmbclient.c:171
AVIO_ENTRY_SHARE
@ AVIO_ENTRY_SHARE
Definition: avio.h:77