diff --git a/HISTORY b/HISTORY index 041dd9e7..2f78bcf9 100644 --- a/HISTORY +++ b/HISTORY @@ -10,6 +10,8 @@ SnapRAID HISTORY * Allow to run a fix command with disks that doesn't need to be fixed mounted as read-only. * Doesn't count empty dirs as files in the diff counters. + * Added a new "share" configuration option to allow to share + in the network the pool directory also in Windows. * Fixed build problem in OpenBSD due the old assembler. 5.1 2013/12 diff --git a/TODO b/TODO index 8a4548d1..ce2f3556 100644 --- a/TODO +++ b/TODO @@ -98,13 +98,6 @@ only if changes are committed after an aborted sync. - Pooling -* Allow to specify the shared path in Windows to access remote symlinks. -Something like: -share \\SERVER\JBOD\ -And then converting all the symbolic links to prepend this path in the link -definition. -Links will appears as \\SERVER\JBOD\DISK_NAME\sub_path_inside_the_disk. - * Add a new "commit" command to move changes from the pool to the array. It should: - Move files copied into the pool (that are no links) to the array. diff --git a/pool.c b/pool.c index 7bd469b2..b86c3118 100644 --- a/pool.c +++ b/pool.c @@ -126,15 +126,24 @@ static int clean_dir(struct snapraid_state* state, const char* dir) /** * Creates a link to the specified disk entry. */ -static void make_link(const char* pool_dir, struct snapraid_disk* disk, const char* sub) +static void make_link(const char* pool_dir, const char* share_dir, struct snapraid_disk* disk, const char* sub) { char path[PATH_MAX]; char linkto[PATH_MAX]; + char linkto_exported[PATH_MAX]; int ret; - /* make the paths */ + /* make the source path */ pathprint(path, sizeof(path), "%s%s", pool_dir, sub); - pathprint(linkto, sizeof(linkto), "%s%s", disk->dir, sub); + + /* make the linkto path */ + if (share_dir[0] != 0) { + /* with a shared directory, use it */ + pathprint(linkto, sizeof(linkto), "%s%s/%s", share_dir, disk->name, sub); + } else { + /* without a share directory, use the local disk paths */ + pathprint(linkto, sizeof(linkto), "%s%s", disk->dir, sub); + } /* create the ancestor directories */ ret = mkancestor(path); @@ -142,8 +151,11 @@ static void make_link(const char* pool_dir, struct snapraid_disk* disk, const ch exit(EXIT_FAILURE); } + /* convert back slashes */ + pathexport(linkto_exported, sizeof(linkto_exported), linkto); + /* create the symlink */ - ret = symlink(linkto, path); + ret = symlink(linkto_exported, path); if (ret != 0) { if (errno == EEXIST) { fprintf(stderr, "WARNING! Duplicate pooling for '%s'\n", path); @@ -163,6 +175,7 @@ void state_pool(struct snapraid_state* state) { tommy_node* i; char pool_dir[PATH_MAX]; + char share_dir[PATH_MAX]; unsigned count; if (state->pool[0] == 0) { @@ -176,6 +189,10 @@ void state_pool(struct snapraid_state* state) pathprint(pool_dir, sizeof(pool_dir), "%s", state->pool); pathslash(pool_dir, sizeof(pool_dir)); + /* share directory with final slash */ + pathprint(share_dir, sizeof(share_dir), "%s", state->share); + pathslash(share_dir, sizeof(share_dir)); + /* first clear the previous pool tree */ clean_dir(state, pool_dir); @@ -190,14 +207,14 @@ void state_pool(struct snapraid_state* state) /* for each file */ for(j=disk->filelist;j!=0;j=j->next) { struct snapraid_file* file = j->data; - make_link(pool_dir, disk, file->sub); + make_link(pool_dir, share_dir, disk, file->sub); ++count; } /* for each link */ for(j=disk->linklist;j!=0;j=j->next) { struct snapraid_link* link = j->data; - make_link(pool_dir, disk, link->sub); + make_link(pool_dir, share_dir, disk, link->sub); ++count; } diff --git a/snapraid.1 b/snapraid.1 index 9d1ae1ef..224c6adc 100644 --- a/snapraid.1 +++ b/snapraid.1 @@ -439,9 +439,61 @@ follow symlinks = yes .RE .PP In Windows the same sharing operation is not so straightforward, -because Windows shares in the network the symbolic links as they are, -and that requires to have modern network clients able to understand -them, that usually doesn\(cqt happen for embedded clients like TVs. +because Windows shares the symbolic links as they are, and that +requires the network clients to resolve them remotely. +.PP +To make it working, besides sharing in the network the pool directory, +you must also share all the disks independently, using as share points +the disk names as defined in the config file. You must also specify in +the \(a"share\(a" option of the configure file, the Windows UNC path that remote +clients needs to use to access such shared disks. +.PP +For example, operating from a server named \(a"darkstar\(a", you can use +the options: +.PP +.RS 4 +disk d1 F:\(rsarray\(rs +.PD 0 +.PP +.PD +disk d2 G:\(rsarray\(rs +.PD 0 +.PP +.PD +disk d3 H:\(rsarray\(rs +.PD 0 +.PP +.PD +pool C:\(rspool +.PD 0 +.PP +.PD +share \(rs\(rsdarkstar +.PD 0 +.PP +.PD +.RE +.PP +and share the following dirs in the network: +.PP +.RS 4 +\(rs\(rsdarkstar\(rspool \-> C:\(rspool +\(rs\(rsdarkstar\(rsd1 \-> F:\(rsarray +\(rs\(rsdarkstar\(rsd2 \-> G:\(rsarray +\(rs\(rsdarkstar\(rsd3 \-> H:\(rsarray +.RE +.PP +to allow remote clients to access all the files at \(rs\(rsdarkstar\(rs\(rspool. +.PP +You may also need to configure remote clients, to enable the access at +remote symlinks with the command: +.PP +.RS 4 +fsutil behavior set SymlinkEvaluation L2L:1 R2R:1 L2R:1 R2L:1 +.PD 0 +.PP +.PD +.RE .SH COMMANDS SnapRAID provides a few simple commands that allow to: .PD 0 @@ -913,7 +965,21 @@ is 1073741824 bytes. .SS pool DIR Defines the pooling directory where the virtual view of the disk array is created using the \(a"pool\(a" command. +.PP The directory must already exist. +.SS share UNC_DIR +Defines the Windows UNC path required to access the disks remotely. +.PP +If this option is specified, the symbolic links created in the pool +directory use this UNC path to access the disks. +Otherwise, the symbolic links will use only local paths, not allowing +to share the pool directory in the network. +.PP +The symbolic links are formed using the specified UNC path, adding the +disk name as specified in the \(a"disk\(a" option, and finally adding the +file dir and name. +.PP +This options is only required for Windows. .SS Examples An example of a typical configuration for Unix is: .PP diff --git a/snapraid.conf.example.windows b/snapraid.conf.example.windows index 3684c4e9..271ac88f 100644 --- a/snapraid.conf.example.windows +++ b/snapraid.conf.example.windows @@ -75,3 +75,14 @@ exclude \Windows\ # Format: "pool DIR" #pool C:\pool +# Defines the Windows UNC path required to access disks from the pooling +# directory when shared in the network. +# If present (uncomment to enable), the symbolic links created in the +# pool virtual view, instead of using local paths, are created using the +# specified UNC path, adding the disk names and file path. +# This allows to share the pool directory in the network. +# See the manual page for more details. +# +# Format: "share UNC_DIR" +#share \\server + diff --git a/snapraid.d b/snapraid.d index 0c08183c..8411bbff 100644 --- a/snapraid.d +++ b/snapraid.d @@ -234,9 +234,37 @@ Getting Started :follow symlinks = yes In Windows the same sharing operation is not so straightforward, - because Windows shares in the network the symbolic links as they are, - and that requires to have modern network clients able to understand - them, that usually doesn't happen for embedded clients like TVs. + because Windows shares the symbolic links as they are, and that + requires the network clients to resolve them remotely. + + To make it working, besides sharing in the network the pool directory, + you must also share all the disks independently, using as share points + the disk names as defined in the config file. You must also specify in + the "share" option of the configure file, the Windows UNC path that remote + clients needs to use to access such shared disks. + + For example, operating from a server named "darkstar", you can use + the options: + + :disk d1 F:\array\ + :disk d2 G:\array\ + :disk d3 H:\array\ + :pool C:\pool + :share \\darkstar + + and share the following dirs in the network: + + \\darkstar\pool -> C:\pool + \\darkstar\d1 -> F:\array + \\darkstar\d2 -> G:\array + \\darkstar\d3 -> H:\array + + to allow remote clients to access all the files at \\darkstar\\pool. + + You may also need to configure remote clients, to enable the access at + remote symlinks with the command: + + :fsutil behavior set SymlinkEvaluation L2L:1 R2R:1 L2R:1 R2L:1 Commands SnapRAID provides a few simple commands that allow to: @@ -717,8 +745,23 @@ Configuration pool DIR Defines the pooling directory where the virtual view of the disk array is created using the "pool" command. + The directory must already exist. + share UNC_DIR + Defines the Windows UNC path required to access the disks remotely. + + If this option is specified, the symbolic links created in the pool + directory use this UNC path to access the disks. + Otherwise, the symbolic links will use only local paths, not allowing + to share the pool directory in the network. + + The symbolic links are formed using the specified UNC path, adding the + disk name as specified in the "disk" option, and finally adding the + file dir and name. + + This options is only required for Windows. + Examples An example of a typical configuration for Unix is: diff --git a/snapraid.txt b/snapraid.txt index 014f7562..d2f22ba1 100644 --- a/snapraid.txt +++ b/snapraid.txt @@ -253,9 +253,37 @@ to your /etc/samba/smb.conf the following options: follow symlinks = yes In Windows the same sharing operation is not so straightforward, -because Windows shares in the network the symbolic links as they are, -and that requires to have modern network clients able to understand -them, that usually doesn't happen for embedded clients like TVs. +because Windows shares the symbolic links as they are, and that +requires the network clients to resolve them remotely. + +To make it working, besides sharing in the network the pool directory, +you must also share all the disks independently, using as share points +the disk names as defined in the config file. You must also specify in +the "share" option of the configure file, the Windows UNC path that remote +clients needs to use to access such shared disks. + +For example, operating from a server named "darkstar", you can use +the options: + + disk d1 F:\array\ + disk d2 G:\array\ + disk d3 H:\array\ + pool C:\pool + share \\darkstar + +and share the following dirs in the network: + + \\darkstar\pool -> C:\pool + \\darkstar\d1 -> F:\array + \\darkstar\d2 -> G:\array + \\darkstar\d3 -> H:\array + +to allow remote clients to access all the files at \\darkstar\\pool. + +You may also need to configure remote clients, to enable the access at +remote symlinks with the command: + + fsutil behavior set SymlinkEvaluation L2L:1 R2R:1 L2R:1 R2L:1 5 COMMANDS @@ -781,8 +809,23 @@ is 1073741824 bytes. ---- 7.8.2 pool DIR ---- Defines the pooling directory where the virtual view of the disk array is created using the "pool" command. + The directory must already exist. +---- 7.8.3 share UNC_DIR ---- +Defines the Windows UNC path required to access the disks remotely. + +If this option is specified, the symbolic links created in the pool +directory use this UNC path to access the disks. +Otherwise, the symbolic links will use only local paths, not allowing +to share the pool directory in the network. + +The symbolic links are formed using the specified UNC path, adding the +disk name as specified in the "disk" option, and finally adding the +file dir and name. + +This options is only required for Windows. + 7.9 Examples ------------ diff --git a/state.c b/state.c index c0f82365..bfac0bf4 100644 --- a/state.c +++ b/state.c @@ -83,6 +83,7 @@ void state_init(struct snapraid_state* state) state->parity_path[l][0] = 0; state->parity_device[l] = 0; } + state->share[0] = 0; state->pool[0] = 0; state->pool_device = 0; state->lockfile[0] = 0; @@ -459,6 +460,24 @@ void state_config(struct snapraid_state* state, const char* path, const char* co /* adjust the level */ if (state->level < l + 1) state->level = l + 1; + } else if (strcmp(tag, "share") == 0) { + if (*state->share) { + fprintf(stderr, "Multiple 'share' specification in '%s' at line %u\n", path, line); + exit(EXIT_FAILURE); + } + + ret = sgetlasttok(f, buffer, sizeof(buffer)); + if (ret < 0) { + fprintf(stderr, "Invalid 'share' specification in '%s' at line %u\n", path, line); + exit(EXIT_FAILURE); + } + + if (!*buffer) { + fprintf(stderr, "Empty 'share' specification in '%s' at line %u\n", path, line); + exit(EXIT_FAILURE); + } + + pathimport(state->share, sizeof(state->share), buffer); } else if (strcmp(tag, "pool") == 0) { struct stat st; diff --git a/state.h b/state.h index ac0e7c88..d68e201e 100644 --- a/state.h +++ b/state.h @@ -90,6 +90,7 @@ struct snapraid_state { unsigned raid_mode; /**< Raid mode to use. RAID_MODE_DEFAULT or RAID_MODE_ALTERNATE. */ char parity_path[LEV_MAX][PATH_MAX]; /**< Path of the parity file. One for each parity. */ uint64_t parity_device[LEV_MAX]; /**< Device identifier of the parity. One for each parity. */ + char share[PATH_MAX]; /**< Path of the share tree. If !=0 pool links are created in a different way. */ char pool[PATH_MAX]; /**< Path of the pool tree. */ uint64_t pool_device; /**< Device identifier of the pool. */ unsigned char hashseed[HASH_SIZE]; /**< Hash seed. Just after a uint64 to provide a minimal alignment. */ diff --git a/test-par1.conf b/test-par1.conf index f33b0700..ccbd556f 100644 --- a/test-par1.conf +++ b/test-par1.conf @@ -11,5 +11,5 @@ disk disk6 test/disk6/ include *.hidden exclude *.unrecoverable pool test/pool - +share \\server\jbod diff --git a/util.c b/util.c index f0f33184..123ccde6 100644 --- a/util.c +++ b/util.c @@ -1172,7 +1172,7 @@ void pathimport(char* dst, size_t size, const char* src) pathcpy(dst, size, src); #ifdef _WIN32 - /* convert all Windows '\' to '/' */ + /* convert all Windows '\' to C '/' */ while (*dst) { if (*dst == '\\') *dst = '/'; @@ -1181,6 +1181,20 @@ void pathimport(char* dst, size_t size, const char* src) #endif } +void pathexport(char* dst, size_t size, const char* src) +{ + pathcpy(dst, size, src); + +#ifdef _WIN32 + /* convert all C '/' to Windows '\' */ + while (*dst) { + if (*dst == '/') + *dst = '\\'; + ++dst; + } +#endif +} + void pathprint(char* dst, size_t size, const char* format, ...) { size_t len; diff --git a/util.h b/util.h index 91369e1b..f63a6613 100644 --- a/util.h +++ b/util.h @@ -410,6 +410,13 @@ void pathcat(char* dst, size_t size, const char* src); */ void pathimport(char* dst, size_t size, const char* src); +/** + * Exports a path limiting the size. + * In Windows all the C slashes are converted to the Windows backslash. + * Aborts if too long. + */ +void pathexport(char* dst, size_t size, const char* src); + /** * Prints a path. * Aborts if too long.