Menu="Share:1"
Title="Share Settings"
---
<?PHP
/* Copyright 2005-2016, Lime Technology
 * Copyright 2012-2016, Bergware International.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License version 2,
 * as published by the Free Software Foundation.
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 */
?>

<?
if ($name == "") {
  /* default values when adding new share */
  $share = ["nameOrig"   => "",
            "name"       => "",
            "comment"    => "",
            "allocator"  => "highwater",
            "floor"      => "",
            "splitLevel" => "",
            "include"    => "",
            "exclude"    => "",
            "useCache"   => "no",
            "cow"        => "auto"];
} elseif (array_key_exists($name, $shares)) {
  /* edit existing share */
  $share = $shares[$name];
} else {
  /* handle share deleted case */
  echo "<p class='notice'>Share ".htmlspecialchars($name)." has been deleted.</p><input type='button' value='Done' onclick='done()'>";
  return;
}

/* check for empty share */
function shareEmpty($name) {
  return (($files = @scandir('/mnt/user/'.$name)) && (count($files) <= 2));
}

function globalInclude($name) {
  global $var;
  return substr($name,0,4)=='disk' && (!$var['shareUserInclude'] || strpos("{$var['shareUserInclude']},","$name,")!==false);
}

// global shares include/exclude
$disks = array_filter($disks,'my_disks');
$myDisks = array_filter(array_diff(array_keys($disks), explode(',',$var['shareUserExclude'])), 'globalInclude');
?>

> A *Share*, also called a *User Share*, is simply the name of a top-level directory that exists on one or more of your
> storage devices (array and cache).  Each share can be exported for network access.  When browsing a share, we return the
> composite view of all files and subdirectories for which that top-level directory exists on each storage device.
>
<?if (!$name):?>
> *Clone source* is used to preset the settings of the new share with the settings of an existing share.
> Select the desired share name and press **Clone** to copy the settings from that source.
<?else:?>
> *Clone destinations* is used to copy the settings of the current share to one or more other existing shares.
> Select the desired destinations and press **Clone** to copy the settings to those shares.
<?endif;?>

<script>
$(function() {
  initDropdown1(false,true);
<?if ($tabbed):?>
  $('#tab1').bind({click:function(){initDropdown1(true,true);}});
<?endif;?>
  setDiskList(document.share_edit.shareUseCache.value);
  presetSpace(document.share_edit.shareFloor);
});
function initDropdown1(remove,create) {
  if (remove) {
    $('#s1').dropdownchecklist('destroy');
    $('#s2').dropdownchecklist('destroy');
<?if ($name):?>
    $('#s3').dropdownchecklist('destroy');
<?endif;?>
  }
  if (create) {
    $("#s1").dropdownchecklist({emptyText:'All', width:300, explicitClose:'...close'});
    $("#s2").dropdownchecklist({emptyText:'None', width:300, explicitClose:'...close'});
<?if ($name):?>
    $("#s3").dropdownchecklist({firstItemChecksAll:true, emptyText:'please select...', width:150, explicitClose:'...close'});
<?endif;?>
  }
}
function setDiskList(cache) {
  var onOff = cache=='only' ? 'disable' : 'enable';
  $("#s1").dropdownchecklist(onOff);
  $("#s2").dropdownchecklist(onOff);
}
function presetSpace(shareFloor) {
  var unit = ['KB','MB','GB','TB','PB'];
  var scale = shareFloor.value;
  if (scale.replace(/[0-9.,\s]/g,'').length>0) return;
  var base = scale>0 ? Math.floor(Math.log(scale)/Math.log(1000)) : 0;
  if (base>=unit.length) base = unit.length-1;
  shareFloor.value = (scale/Math.pow(1000, base))+unit[base];
}
// Compose input fields
function prepareEdit(form) {
// Test share name validity
  var share = form.shareName.value.trim();
  if (share.length==0) {
    swal('Missing share name', 'Enter a name for the share', 'error');
    return false;
  }
  if (share.match('^(disk[0-9]+|cache[0-9]*|flash)$')) {
    swal('Invalid share name', 'Do not use reserved names', 'error');
    return false;
  }
  form.shareName.value = share;
// Adjust minimum free space value to selected unit
  var unit = 'KB,MB,GB,TB,PB';
  var scale = form.shareFloor.value;
  var index = unit.indexOf(scale.replace(/[0-9.,\s]/g,'').toUpperCase());
  form.shareFloor.value = scale.replace(/[A-Z\s]/gi,'') * Math.pow(1000, (index>0 ? index/3 : 0))
// Return include as single line input
  var include = '';
  for (var i=0,item; item=form.shareInclude.options[i]; i++) {
    if (item.selected) {
      if (include.length) include += ',';
      include += item.value;
      item.selected = false;
    }
  }
  item = form.shareInclude.options[0];
  item.value = include;
  item.selected = true;
// Return exclude as single line input
  var exclude = '';
  for (var i=0,item; item=form.shareExclude.options[i]; i++) {
    if (item.selected) {
      if (exclude.length) exclude += ',';
      exclude += item.value;
      item.selected = false;
    }
  }
  item = form.shareExclude.options[0];
  item.value = exclude;
  item.selected = true;
  return true;
}
<?if ($name):?>
function cloneShare() {
  var data = {}, copied = false;
  data.shareAllocator = '<?=addslashes(htmlspecialchars($share['allocator']))?>';
  data.shareFloor = '<?=addslashes(htmlspecialchars($share['floor']))?>';
  data.shareSplitLevel = '<?=addslashes(htmlspecialchars($share['splitLevel']))?>';
  data.shareInclude = '<?=addslashes(htmlspecialchars($share['include']))?>';
  data.shareExclude = '<?=addslashes(htmlspecialchars($share['exclude']))?>';
  data.shareUseCache = '<?=addslashes(htmlspecialchars($share['useCache']))?>';
  data.cmdEditShare = 'Apply';
  $('select#s3 option').map(function() {
    if ($(this).prop('selected')==true) {
      data.shareNameOrig = $(this).val();
      data.shareName = $(this).val();
      $.post('/update.htm', data);
      copied = true;
    }
  });
  if (copied) swal({title:'Clone complete',text:'Share settings are cloned to the selected shares',type:'success'},function(){refresh();});
}
<?else:?>
function cloneShare() {
  var form = document.share_edit;
  var name = $('select[name="shareClone"]').val();
  initDropdown1(true,false);
  $.get('/webGui/include/ShareData.php',{name:name},function(json) {
    var data = $.parseJSON(json);
    form.shareAllocator.value = data.allocator;
    form.shareFloor.value = data.floor;
    form.shareSplitLevel.value = data.splitLevel;
    form.shareInclude.value = data.include;
    form.shareExclude.value = data.exclude;
    form.shareUseCache.value = data.useCache;
    form.shareCOW.value = data.cow;
    for (var i=0,disk; disk=data.include.split(',')[i]; i++) for (var j=0,include; include=form.shareInclude.options[j]; j++) if (include.value==disk) include.selected=true;
    for (var i=0,disk; disk=data.exclude.split(',')[i]; i++) for (var j=0,exclude; exclude=form.shareExclude.options[j]; j++) if (exclude.value==disk) exclude.selected=true;
    initDropdown1(false,true);
  });
}
<?endif;?>
</script>
<div style="float:right">
<?if ($name):?>
<span style="display:block;font-weight:bold;margin-left:2px;margin-bottom:4px">Clone destinations</span>
<select id="s3" name="shareClone" size="1" multiple="multiple" style="display:none">
<option>All</option>
<?foreach ($shares as $list) if ($list['name']!=$name) echo mk_option("", $list['name'], $list['name']);?>
</select>
<div style="margin-top:10px;text-align:right"><input type="button" id="cloneshare" value="Clone" onclick="cloneShare()" style="margin-right:0"></div>
<?else:?>
<span style="display:block;font-weight:bold;margin-left:2px;margin-bottom:4px">Clone source</span>
<select name="shareClone" size="1" onchange="$('#cloneshare').prop('disabled',false)">
<option disabled selected>please select...</option>
<?foreach ($shares as $list) echo mk_option("", $list['name'], $list['name']);?>
</select>
<div style="margin-top:10px"><input type="button" id="cloneshare" value="Clone" onclick="cloneShare()" disabled></div>
<?endif;?>
</div>

<form markdown="1" name="share_edit" method="POST" action="/update.htm" target="progressFrame" onsubmit="return prepareEdit(this)" onchange="$('#cloneshare').prop('disabled',true);$('#s3').dropdownchecklist('disable')">
<input type="hidden" name="shareNameOrig" value="<?=htmlspecialchars($share['nameOrig'])?>">

Share name:
: <input type="text" name="shareName" maxlength="40" value="<?=htmlspecialchars($name)?>">

> The share name can be up to 40 characters, and is case-sensitive with these restrictions:
>
> * cannot contain a double-quote character (")
> * cannot be one of the reserved share names: flash, cache, cach2, .., disk1, disk2, ..
>
> We highly recommend to make your life easier and avoid special characters.

Comments:
: <input type="text" name="shareComment" maxlength="256" value="<?=htmlspecialchars($share['comment'])?>">

> Anything you like, up to 256 characters.

Allocation method:
: <select name="shareAllocator" size="1">
  <?=mk_option($share['allocator'], "highwater", "High-water")?>
  <?=mk_option($share['allocator'], "fillup", "Fill-up")?>
  <?=mk_option($share['allocator'], "mostfree", "Most-free")?>
  </select>

> This setting determines how unRAID OS will choose which disk to use when creating a new file or directory:
>
> **High-water**
> Choose the lowest numbered disk with free space still above the current *high water mark*.  The
> *high water mark* is initialized with the size of the largest data disk divided by 2.  If no disk
> has free space above the current *high water mark*, divide the *high water mark* by 2 and choose again.
>
> The goal of **High-water** is to write as much data as possible to each disk (in order to minimize
> how often disks need to be spun up), while at the same time, try to keep the same amount of free space on
> each disk (in order to distribute data evenly across the array).
>
> **Fill-up**
> Choose the lowest numbered disk that still has free space above the current **Minimum free space**
> setting.
>
> **Most-free**
> Choose the disk that currently has the most free space.

Minimum free space:
: <input type="text" name="shareFloor" maxlength="16" value="<?=htmlspecialchars($share['floor'])?>">

> The *minimum free space* available to allow writing to any disk belonging to the share.<br>
>
> Choose a value which is equal or greater than the biggest single file size you intend to copy to the share.
> Include units KB, MB, GB and TB as appropriate, e.g. 10MB.

Split level:
: <select name="shareSplitLevel" size="1" style="width:320px">
  <?=mk_option($share['splitLevel'], "", "Automatically split any directory as required")?>
  <?=mk_option($share['splitLevel'], "1", "Automatically split only the top level directory as required")?>
  <?=mk_option($share['splitLevel'], "2", "Automatically split only the top two directory levels as required")?>
  <?=mk_option($share['splitLevel'], "3", "Automatically split only the top three directory levels as required")?>
  <?=mk_option($share['splitLevel'], "4", "Automatically split only the top four directory levels as required")?>
  <?=mk_option($share['splitLevel'], "5", "Automatically split only the top five directory levels as required")?>
  <?=mk_option($share['splitLevel'], "0", "Manual: do not automatically split directories")?>
  </select>

> Determines whether a directory is allowed to expand onto multiple disks.

> **Automatically split any directory as required**
> When a new file or subdirectory needs to be created in a share, unRAID OS first chooses which disk
> it should be created on, according to the configured *Allocation method*.  If the parent directory containing
> the new file or or subdirectory does not exist on this disk, then unRAID OS will first create all necessary
> parent directories, and then create the new file or subdirectory.
>
> **Automatically split only the top level directory as required**
> When a new file or subdirectory is being created in the first level subdirectory of a share, if that first
> level subdirectory does not exist on the disk being written, then the subdirectory will be created first.
> If a new file or subdirectory is being created in the second or lower level subdirectory of a share, the new
> file or subdirectory is created on the same disk as the new file or subdirectorys parent directory.
>
> **Automatically split only the top "N" level directories as required**
> Similar to previous: when a new file or subdirectory is being created, if the parent directory is at level "N",
> and does not exist on the chosen disk, unRAID OS will first create all necessary parent directories.  If the
> parent directory of the new file or subdirectory is beyond level "N", then the new file or subdirectory is
> created on the same disk where the parent directory exists.
>
> **Manual: do not automatically split directories**
> When a new file or subdirectory needs to be created in a share, unRAID OS will only consider disks where the
> parent directory already exists.

Included disk(s):
: <select id="s1" name="shareInclude" size="1" multiple="multiple" style="display:none">
  <?foreach ($myDisks as $disk):?>
  <?=mk_option_check($disk, $share['include'])?>
  <?endforeach;?>
  </select>

> Specify the disks which can be used by the share. By default all disks are included; that is, if specific
> disks are not selected here, then the share may expand into *all* array disks.

Excluded disk(s):
: <select id="s2" name="shareExclude" size="1" multiple="multiple" style="display:none">
  <?foreach ($myDisks as $disk):?>
  <?=mk_option_check($disk, $share['exclude'])?>
  <?endforeach;?>
  </select>

> Specify the disks which can *not* be used by the share. By default no disks are excluded.

Use cache disk:
: <select name="shareUseCache" size="1" onchange="setDiskList(this.value)">
  <?=mk_option($share['useCache'], "no", "No")?>
  <?=mk_option($share['useCache'], "yes", "Yes")?>
  <?=mk_option($share['useCache'], "only", "Only")?>
  <?=mk_option($share['useCache'], "prefer", "Prefer")?>
  </select>

> Specify whether new files and directories written on the share can be written onto the Cache disk/pool
> if present.
>
> **No** prohibits new files and subdirectories from being written onto the Cache disk/pool.
>
> **Yes** indicates that all new files and subdirectories should be written to the Cache disk/pool, provided
> enough free space exists on the Cache disk/pool.  If there is insufficient space on the Cache disk/pool, then
> new files and directories are created on the array.  When the *mover* is invoked, files and subdirectories are
> transferred off the Cache disk/pool and onto the array.
>
> **Only** indicates that all new files and subdirectories must be writen to the Cache disk/pool.  If there
> is insufficient free space on the Cache disk/pool, *create* operations will fail with *out of space* status.
>
> **Prefer** indicates that all new files and subdirectories should be written to the Cache disk/pool, provided
> enough free space exists on the Cache disk/pool.  If there is insufficient space on the Cache disk/pool, then
> new files and directories are created on the array.  When the *mover* is invoked, files and subdirectories are
> transferred off the array and onto Cache disk/pool.

Enable Copy-on-write:
: <select name="shareCOW" size="1"<?if ($name):?> disabled<?endif;?>>
  <?=mk_option($share['cow'], "no", "No")?>
  <?=mk_option($share['cow'], "auto", "Auto")?>
  </select><?if ($name):?>Set when adding new share only.<?endif;?>

> Set to **No** to cause the *btrfs* NOCOW (No Copy-on-Write) attribute to be set on the share directory
> when created on a device formatted with *btrfs* file system.  Once set, newly created files and
> subdirectories on the device will inherit the NOCOW attribute.  We recommend this setting for shares
> used to store vdisk images, including the Docker loopback image file.  This setting has no effect
> on non-btrfs file systems.
>
> Set to **Auto** for normal operation, meaning COW **will** be in effect on devices formatted with *btrfs*.

<?if (!$name):?>
&nbsp;
: <input type="submit" name="cmdEditShare" value="Add Share"><input type="button" value="Done" onclick="done()">
<?elseif (shareEmpty($name)):?>
Share status:
: <span class="big">Share is empty</span>

> Share does *not* contain any data and may be deleted if not needed any longer.

Delete<input type="checkbox" name="confirmDelete" onchange="chkDelete(this.form, this.form.cmdEditShare);">
: <input type="submit" name="cmdEditShare" value="Apply"><input type="button" value="Done" onclick="done()">
<?else:?>
Share status:
: <span class="big">Share contains data</span>

> Share can *not* be deleted as long as it contains data. Be aware that some data can be hidden. See also [SMB Settings](/Settings/SMB) -> Hide "dot" files.

&nbsp;
: <input type="submit" name="cmdEditShare" value="Apply"><input type="button" value="Done" onclick="done()">
<?endif;?>
</form>
