"Fossies" - the Fresh Open Source Software Archive

Member "smbnetfs-0.6.3/src/samba.c" (1 Feb 2018, 14086 Bytes) of package /linux/misc/smbnetfs-0.6.3.tar.bz2:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "samba.c" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 0.6.1_vs_0.6.2.

    1 #include "config.h"
    2 #include <errno.h>
    3 #include <stdio.h>
    4 #include <stdlib.h>
    5 #include <string.h>
    6 #include <pthread.h>
    7 
    8 #include "list.h"
    9 #include "smb_conn.h"
   10 #include "samba.h"
   11 #include "common.h"
   12 
   13 struct samba_ctx{
   14     LIST        entries;
   15     int         ref_count;
   16     struct smb_conn_ctx smb_ctx;
   17     char        name[128];
   18 };
   19 
   20 #define smb_conn_ctx_to_samba_ctx(ptr)  \
   21     (struct samba_ctx *)((char*)(ptr) - offsetof(struct samba_ctx, smb_ctx))
   22 
   23 static size_t       samba_max_rw_block_size = (128 * 1024);
   24 static int      samba_ctx_count     = 0;
   25 static int      samba_ctx_max_count = 15;
   26 static LIST     samba_ctx_list      = STATIC_LIST_INITIALIZER(samba_ctx_list);
   27 static pthread_mutex_t  m_samba         = PTHREAD_MUTEX_INITIALIZER;
   28 
   29 
   30 int samba_init(size_t max_rw_block_size){
   31     size_t  page_size;
   32 
   33     page_size = getpagesize();
   34     max_rw_block_size -= (max_rw_block_size % page_size);
   35     if (max_rw_block_size == 0) max_rw_block_size = page_size;
   36 
   37     samba_max_rw_block_size = max_rw_block_size;
   38     DPRINTF(7, "max_rw_block_size=%zd\n", samba_max_rw_block_size);
   39     return 1;
   40 }
   41 
   42 static void samba_set_context_name(struct samba_ctx *ctx, const char *name, size_t len){
   43     if (len >= sizeof(ctx->name)) len = sizeof(ctx->name) - 1;
   44     if (len > 0) strncpy(ctx->name, name, len);
   45     ctx->name[len] = '\0';
   46 }
   47 
   48 static struct samba_ctx * samba_add_new_context(const char *name, size_t len){
   49     struct samba_ctx    *ctx;
   50 
   51     ctx = malloc(sizeof(struct samba_ctx));
   52     if (ctx == NULL) return NULL;
   53     memset(ctx, 0, sizeof(struct samba_ctx));
   54     if (smb_conn_ctx_init(&ctx->smb_ctx, samba_max_rw_block_size) != 0){
   55     free(ctx);
   56     return NULL;
   57     }
   58     samba_set_context_name(ctx, name, len);
   59     add_to_list_back(&samba_ctx_list, &ctx->entries);
   60     samba_ctx_count++;
   61     return ctx;
   62 }
   63 
   64 static int samba_try_to_remove_context(struct samba_ctx *ctx){
   65     if (ctx->ref_count != 0) return -1;
   66     if (smb_conn_ctx_destroy(&ctx->smb_ctx) != 0) return -1;
   67     samba_ctx_count--;
   68     remove_from_list(&samba_ctx_list, &ctx->entries);
   69     return 0;
   70 }
   71 
   72 static struct samba_ctx * samba_find_by_name(const char *name, size_t len){
   73     struct samba_ctx    *ctx;
   74     LIST        *elem;
   75 
   76     if (len >= sizeof(ctx->name)) len = sizeof(ctx->name) - 1;
   77     elem = first_list_elem(&samba_ctx_list);
   78     while(is_valid_list_elem(&samba_ctx_list, elem)){
   79     ctx = list_entry(elem, struct samba_ctx, entries);
   80     if ((strncasecmp(ctx->name, name, len) == 0) &&
   81         (ctx->name[len] == '\0')) return ctx;
   82     elem = elem->next;
   83     };
   84     return NULL;
   85 }
   86 
   87 static struct samba_ctx * samba_find_oldest(void){
   88     /* our list is sorted by the usage time, so the last element is oldest */
   89     LIST *elem = last_list_elem(&samba_ctx_list);
   90     if (is_valid_list_elem(&samba_ctx_list, elem))
   91     return list_entry(elem, struct samba_ctx, entries);
   92     return NULL;
   93 }
   94 
   95 static const char* samba_get_context_status_string(void){
   96     static char     buffer[4096];
   97     LIST        *elem;
   98     int         ret;
   99     size_t      len;
  100     char        *pos, *ptn;
  101 
  102     memset(buffer, 0, sizeof(buffer));
  103     len = sizeof(buffer); pos = buffer; ptn = "%s[%d], ";
  104 
  105     *pos++ = '('; len--;
  106     elem = first_list_elem(&samba_ctx_list);
  107     while(is_valid_list_elem(&samba_ctx_list, elem)){
  108     struct samba_ctx    *ctx;
  109 
  110     ctx = list_entry(elem, struct samba_ctx, entries);
  111     if (!is_valid_list_elem(&samba_ctx_list, elem->next)) ptn = "%s[%d]";
  112     ret = snprintf(pos, len, ptn, ctx->name, ctx->ref_count);
  113     if (ret < 0) goto error;
  114     if ((size_t) ret >= len) goto out_of_space;
  115     pos += ret; len -= ret;
  116     elem = elem->next;
  117     };
  118     if (len < 2) goto out_of_space;
  119     *pos++ = ')';
  120     *pos = '\0';
  121     return buffer;
  122 
  123   out_of_space:
  124     strcpy(buffer + sizeof(buffer) - 5, "...)");
  125     return buffer;
  126 
  127   error:
  128     return "(?error?)";
  129 }
  130 
  131 /* our list is sorted by the usage time, so touching is equivalent */
  132 /* to the moving of element to the top of the list */
  133 static inline void samba_touch_ctx_without_lock(struct samba_ctx *ctx){
  134     remove_from_list(&samba_ctx_list, &ctx->entries);
  135     add_to_list(&samba_ctx_list, &ctx->entries);
  136 }
  137 
  138 /* the same as above, but with locking */
  139 static void samba_touch_ctx(struct samba_ctx *ctx){
  140     pthread_mutex_lock(&m_samba);
  141     samba_touch_ctx_without_lock(ctx);
  142     pthread_mutex_unlock(&m_samba);
  143 }
  144 
  145 int samba_set_max_ctx_count(int count){
  146     if (count < 3) return 0;
  147     DPRINTF(7, "count=%d\n", count);
  148     pthread_mutex_lock(&m_samba);
  149     samba_ctx_max_count = count;
  150     pthread_mutex_unlock(&m_samba);
  151     return 1;
  152 }
  153 
  154 void samba_allocate_ctxs(void){
  155     struct samba_ctx    *ctx;
  156 
  157     pthread_mutex_lock(&m_samba);
  158     while(samba_ctx_count < samba_ctx_max_count){
  159     if ((ctx = samba_add_new_context("", 0)) == NULL) break;
  160     }
  161     pthread_mutex_unlock(&m_samba);
  162 }
  163 
  164 void samba_destroy_unused_ctxs(void){
  165     LIST        *elem;
  166     struct samba_ctx    *ctx;
  167 
  168     pthread_mutex_lock(&m_samba);
  169     elem = first_list_elem(&samba_ctx_list);
  170     while(is_valid_list_elem(&samba_ctx_list, elem)){
  171     ctx = list_entry(elem, struct samba_ctx, entries);
  172     elem = elem->next;
  173     if (ctx->ref_count == 0) samba_try_to_remove_context(ctx);
  174     }
  175     DPRINTF(6, "ctx_total=%d, list=%s\n",
  176     samba_ctx_count, samba_get_context_status_string());
  177     pthread_mutex_unlock(&m_samba);
  178 }
  179 
  180 static struct samba_ctx * samba_get_ctx(const char *url){
  181     size_t      len;
  182     struct samba_ctx    *ctx;
  183 
  184     /* find a length of first component of url's path */
  185     for(len = 0; url[len] == '/'; len++);
  186     for(; (url[len] != '\0') && (url[len] != '/'); len++);
  187     DPRINTF(6, "name='%.*s'\n", (int) len, url);
  188 
  189     pthread_mutex_lock(&m_samba);
  190     if ((ctx = samba_find_by_name(url, len)) != NULL) goto exist;
  191     if (samba_ctx_count < samba_ctx_max_count)
  192     if ((ctx = samba_add_new_context(url, len)) != NULL) goto exist;
  193     if ((ctx = samba_find_oldest()) == NULL) goto shit_happens;
  194 
  195     /* reuse oldest context for new purpose */
  196     samba_set_context_name(ctx, url, len);
  197 
  198   exist:
  199     /* touch ctx and increase its ref_count */
  200     samba_touch_ctx_without_lock(ctx);
  201     ctx->ref_count++;
  202 
  203   shit_happens:
  204     DPRINTF(6, "ctx_total=%d, list=%s\n",
  205     samba_ctx_count, samba_get_context_status_string());
  206     pthread_mutex_unlock(&m_samba);
  207     return ctx;
  208 }
  209 
  210 static void samba_release_ctx(struct samba_ctx *ctx){
  211     pthread_mutex_lock(&m_samba);
  212     DPRINTF(6, "ctx->name=%s[%d]\n", ctx->name, ctx->ref_count);
  213     if (ctx->ref_count > 0){
  214     ctx->ref_count--;
  215     if ((samba_ctx_count > samba_ctx_max_count) && (ctx->ref_count == 0))
  216         samba_try_to_remove_context(ctx);
  217     }else{
  218     DPRINTF(0, "WARNING! trying to release an unused context!\n");
  219     }
  220     DPRINTF(6, "ctx_total=%d, list=%s\n",
  221     samba_ctx_count, samba_get_context_status_string());
  222     pthread_mutex_unlock(&m_samba);
  223 }
  224 
  225 samba_fd samba_open(const char *url, int flags, mode_t mode){
  226     int         error;
  227     struct samba_ctx    *ctx;
  228     samba_fd        fd;
  229 
  230     if ((ctx = samba_get_ctx(url)) == NULL){
  231     errno = ENOMEM;
  232     return NULL;
  233     }
  234     fd = smb_conn_open(&ctx->smb_ctx, url, flags, mode);
  235     error = errno;
  236     if (fd == NULL) samba_release_ctx(ctx);
  237     errno = error;
  238     return fd;
  239 }
  240 
  241 samba_fd samba_creat(const char *url, mode_t mode){
  242     int         error;
  243     struct samba_ctx    *ctx;
  244     samba_fd        fd;
  245 
  246     if ((ctx = samba_get_ctx(url)) == NULL){
  247     errno = ENOMEM;
  248     return NULL;
  249     }
  250     fd = smb_conn_creat(&ctx->smb_ctx, url, mode);
  251     error = errno;
  252     if (fd == NULL) samba_release_ctx(ctx);
  253     errno = error;
  254     return fd;
  255 }
  256 
  257 ssize_t samba_read(samba_fd fd, off_t offset, char *buf, size_t bufsize){
  258     ssize_t result = 0;
  259 
  260     if ((fd == NULL) || (fd->ctx == NULL)){
  261     errno = EINVAL;
  262     return -1;
  263     }
  264     samba_touch_ctx(smb_conn_ctx_to_samba_ctx(fd->ctx));
  265     while(bufsize > 0){
  266     ssize_t     res;
  267     size_t      count;
  268 
  269     count = (bufsize <= samba_max_rw_block_size) ?
  270             bufsize : samba_max_rw_block_size;
  271     res = smb_conn_read(fd->ctx, fd, offset, buf, count);
  272     if (res == (ssize_t) (-1)) return res;
  273     buf += res; offset += res; bufsize -= res;
  274     result += res;
  275     if (res != (ssize_t) count) break;
  276     }
  277     return result;
  278 }
  279 
  280 ssize_t samba_write(samba_fd fd, off_t offset, const char *buf, size_t bufsize){
  281     ssize_t result = 0;
  282 
  283     if ((fd == NULL) || (fd->ctx == NULL)){
  284     errno = EINVAL;
  285     return -1;
  286     }
  287     samba_touch_ctx(smb_conn_ctx_to_samba_ctx(fd->ctx));
  288     while(bufsize > 0){
  289     ssize_t     res;
  290     size_t      count;
  291 
  292     count = (bufsize <= samba_max_rw_block_size) ?
  293             bufsize : samba_max_rw_block_size;
  294     res = smb_conn_write(fd->ctx, fd, offset, buf, count);
  295     if (res == (ssize_t) (-1)) return res;
  296     buf += res; offset += res; bufsize -= res;
  297     result += res;
  298     if (res != (ssize_t) count) break;
  299     }
  300     return result;
  301 }
  302 
  303 int samba_close(samba_fd fd){
  304     int         error, result;
  305     struct smb_conn_ctx *ctx;
  306 
  307     if ((fd == NULL) || (fd->ctx == NULL)){
  308     errno = EINVAL;
  309     return -1;
  310     }
  311     ctx = fd->ctx;
  312     result = smb_conn_close(ctx, fd);
  313     error = errno;
  314     if (result == 0) samba_release_ctx(smb_conn_ctx_to_samba_ctx(ctx));
  315     errno = error;
  316     return result;
  317 }
  318 
  319 int samba_unlink(const char *url){
  320     int         error, result;
  321     struct samba_ctx    *ctx;
  322 
  323     if ((ctx = samba_get_ctx(url)) == NULL){
  324     errno = ENOMEM;
  325     return -1;
  326     }
  327     result = smb_conn_unlink(&ctx->smb_ctx, url);
  328     error = errno;
  329     samba_release_ctx(ctx);
  330     errno = error;
  331     return result;
  332 }
  333 
  334 int samba_rename(const char *old_url, const char *new_url){
  335     int         error, result;
  336     struct samba_ctx    *ctx;
  337 
  338     if ((ctx = samba_get_ctx(old_url)) == NULL){
  339     errno = ENOMEM;
  340     return -1;
  341     }
  342     result = smb_conn_rename(&ctx->smb_ctx, old_url, new_url);
  343     error = errno;
  344     samba_release_ctx(ctx);
  345     errno = error;
  346     return result;
  347 }
  348 
  349 samba_fd samba_opendir(const char *url){
  350     int         error;
  351     struct samba_ctx    *ctx;
  352     samba_fd        fd;
  353 
  354     if ((ctx = samba_get_ctx(url)) == NULL){
  355     errno = ENOMEM;
  356     return NULL;
  357     }
  358     fd = smb_conn_opendir(&ctx->smb_ctx, url);
  359     error = errno;
  360     if (fd == NULL) samba_release_ctx(ctx);
  361     errno = error;
  362     return fd;
  363 }
  364 
  365 int samba_closedir(samba_fd fd){
  366     int         error, result;
  367     struct smb_conn_ctx *ctx;
  368 
  369     if ((fd == NULL) || (fd->ctx == NULL)){
  370     errno = EINVAL;
  371     return -1;
  372     }
  373     ctx = fd->ctx;
  374     result = smb_conn_closedir(ctx, fd);
  375     error = errno;
  376     if (result == 0) samba_release_ctx(smb_conn_ctx_to_samba_ctx(ctx));
  377     errno = error;
  378     return result;
  379 }
  380 
  381 ssize_t samba_readdir(samba_fd fd, void *buf, size_t bufsize){
  382     if ((fd == NULL) || (fd->ctx == NULL)){
  383     errno = EINVAL;
  384     return -1;
  385     }
  386     samba_touch_ctx(smb_conn_ctx_to_samba_ctx(fd->ctx));
  387     return smb_conn_readdir(fd->ctx, fd, buf, bufsize);
  388 }
  389 
  390 int samba_mkdir(const char *url, mode_t mode){
  391     int         error, result;
  392     struct samba_ctx    *ctx;
  393 
  394     if ((ctx = samba_get_ctx(url)) == NULL){
  395     errno = ENOMEM;
  396     return -1;
  397     }
  398     result = smb_conn_mkdir(&ctx->smb_ctx, url, mode);
  399     error = errno;
  400     samba_release_ctx(ctx);
  401     errno = error;
  402     return result;
  403 }
  404 
  405 int samba_rmdir(const char *url){
  406     int         error, result;
  407     struct samba_ctx    *ctx;
  408 
  409     if ((ctx = samba_get_ctx(url)) == NULL){
  410     errno = ENOMEM;
  411     return -1;
  412     }
  413     result = smb_conn_rmdir(&ctx->smb_ctx, url);
  414     error = errno;
  415     samba_release_ctx(ctx);
  416     errno = error;
  417     return result;
  418 }
  419 
  420 int samba_stat (const char *url, struct stat *st){
  421     int         error, result;
  422     struct samba_ctx    *ctx;
  423 
  424     if ((ctx = samba_get_ctx(url)) == NULL){
  425     errno = ENOMEM;
  426     return -1;
  427     }
  428     result = smb_conn_stat(&ctx->smb_ctx, url, st);
  429     error = errno;
  430     samba_release_ctx(ctx);
  431     errno = error;
  432     return result;
  433 }
  434 
  435 int samba_fstat(samba_fd fd, struct stat *st){
  436     if ((fd == NULL) || (fd->ctx == NULL)){
  437     errno = EINVAL;
  438     return -1;
  439     }
  440     samba_touch_ctx(smb_conn_ctx_to_samba_ctx(fd->ctx));
  441     return smb_conn_fstat(fd->ctx, fd, st);
  442 }
  443 
  444 int samba_ftruncate(samba_fd fd, off_t size){
  445     if ((fd == NULL) || (fd->ctx == NULL)){
  446     errno = EINVAL;
  447     return -1;
  448     }
  449     samba_touch_ctx(smb_conn_ctx_to_samba_ctx(fd->ctx));
  450     return smb_conn_ftruncate(fd->ctx, fd, size);
  451 }
  452 
  453 int samba_chmod(const char *url, mode_t mode){
  454     int         error, result;
  455     struct samba_ctx    *ctx;
  456 
  457     if ((ctx = samba_get_ctx(url)) == NULL){
  458     errno = ENOMEM;
  459     return -1;
  460     }
  461     result = smb_conn_chmod(&ctx->smb_ctx, url, mode);
  462     error = errno;
  463     samba_release_ctx(ctx);
  464     errno = error;
  465     return result;
  466 }
  467 
  468 int samba_utimes(const char *url, struct timeval *tbuf){
  469     int         error, result;
  470     struct samba_ctx    *ctx;
  471 
  472     if ((ctx = samba_get_ctx(url)) == NULL){
  473     errno = ENOMEM;
  474     return -1;
  475     }
  476     result = smb_conn_utimes(&ctx->smb_ctx, url, tbuf);
  477     error = errno;
  478     samba_release_ctx(ctx);
  479     errno = error;
  480     return result;
  481 }
  482 
  483 int samba_setxattr(const char *url, const char *name,
  484         const void *value, size_t size, int flags){
  485 
  486     int         error, result;
  487     struct samba_ctx    *ctx;
  488 
  489     if ((ctx = samba_get_ctx(url)) == NULL){
  490     errno = ENOMEM;
  491     return -1;
  492     }
  493     result = smb_conn_setxattr(&ctx->smb_ctx, url, name, value, size, flags);
  494     error = errno;
  495     samba_release_ctx(ctx);
  496     errno = error;
  497     return result;
  498 }
  499 
  500 int samba_getxattr(const char *url, const char *name,
  501         void *value, size_t size){
  502 
  503     int         error, result;
  504     struct samba_ctx    *ctx;
  505 
  506     if ((ctx = samba_get_ctx(url)) == NULL){
  507     errno = ENOMEM;
  508     return -1;
  509     }
  510     result = smb_conn_getxattr(&ctx->smb_ctx, url, name, value, size);
  511     error = errno;
  512     samba_release_ctx(ctx);
  513     errno = error;
  514     return result;
  515 }
  516 
  517 int samba_listxattr(const char *url, char *list, size_t size){
  518     int         error, result;
  519     struct samba_ctx    *ctx;
  520 
  521     if ((ctx = samba_get_ctx(url)) == NULL){
  522     errno = ENOMEM;
  523     return -1;
  524     }
  525     result = smb_conn_listxattr(&ctx->smb_ctx, url, list, size);
  526     error = errno;
  527     samba_release_ctx(ctx);
  528     errno = error;
  529     return result;
  530 }
  531 
  532 int samba_removexattr(const char *url, const char *name){
  533     int         error, result;
  534     struct samba_ctx    *ctx;
  535 
  536     if ((ctx = samba_get_ctx(url)) == NULL){
  537     errno = ENOMEM;
  538     return -1;
  539     }
  540     result = smb_conn_removexattr(&ctx->smb_ctx, url, name);
  541     error = errno;
  542     samba_release_ctx(ctx);
  543     errno = error;
  544     return result;
  545 }