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