| 331 | } |
| 332 | |
| 333 | static int libssh_read_dir(URLContext *h, AVIODirEntry **next) |
| 334 | { |
| 335 | LIBSSHContext *libssh = h->priv_data; |
| 336 | sftp_attributes attr = NULL; |
| 337 | AVIODirEntry *entry; |
| 338 | |
| 339 | *next = entry = ff_alloc_dir_entry(); |
| 340 | if (!entry) |
| 341 | return AVERROR(ENOMEM); |
| 342 | |
| 343 | do { |
| 344 | if (attr) |
| 345 | sftp_attributes_free(attr); |
| 346 | attr = sftp_readdir(libssh->sftp, libssh->dir); |
| 347 | if (!attr) { |
| 348 | av_freep(next); |
| 349 | if (sftp_dir_eof(libssh->dir)) |
| 350 | return 0; |
| 351 | return AVERROR(EIO); |
| 352 | } |
| 353 | } while (!strcmp(attr->name, ".") || !strcmp(attr->name, "..")); |
| 354 | |
| 355 | entry->name = av_strdup(attr->name); |
| 356 | entry->group_id = attr->gid; |
| 357 | entry->user_id = attr->uid; |
| 358 | entry->size = attr->size; |
| 359 | entry->access_timestamp = INT64_C(1000000) * attr->atime; |
| 360 | entry->modification_timestamp = INT64_C(1000000) * attr->mtime; |
| 361 | entry->filemode = attr->permissions & 0777; |
| 362 | switch(attr->type) { |
| 363 | case SSH_FILEXFER_TYPE_REGULAR: |
| 364 | entry->type = AVIO_ENTRY_FILE; |
| 365 | break; |
| 366 | case SSH_FILEXFER_TYPE_DIRECTORY: |
| 367 | entry->type = AVIO_ENTRY_DIRECTORY; |
| 368 | break; |
| 369 | case SSH_FILEXFER_TYPE_SYMLINK: |
| 370 | entry->type = AVIO_ENTRY_SYMBOLIC_LINK; |
| 371 | break; |
| 372 | case SSH_FILEXFER_TYPE_SPECIAL: |
| 373 | /* Special type includes: sockets, char devices, block devices and pipes. |
| 374 | It is probably better to return unknown type, to not confuse anybody. */ |
| 375 | case SSH_FILEXFER_TYPE_UNKNOWN: |
| 376 | default: |
| 377 | entry->type = AVIO_ENTRY_UNKNOWN; |
| 378 | } |
| 379 | sftp_attributes_free(attr); |
| 380 | return 0; |
| 381 | } |
| 382 | |
| 383 | static int libssh_close_dir(URLContext *h) |
| 384 | { |
nothing calls this directly
no test coverage detected