/*
*/
/*
* BSD 3 Clause License
*
* Copyright (c) 2007, The Storage Networking Industry Association.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* distribution.
*
* - Neither the name of The Storage Networking Industry Association (SNIA)
* nor the names of its contributors may be used to endorse or promote
* products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/*
* This file implemets the post-order, pre-order and level-order
* traversing of the file system. The related macros and constants
* are defined in traverse.h.
*/
#include <assert.h>
#include <cstack.h>
#include <dirent.h>
#include <errno.h>
#include <traverse.h>
#include <limits.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <syslog.h>
#include <fcntl.h>
#include <unistd.h>
#include <tlm.h>
#include "tlm_proto.h"
/*
* Check if it's "." or ".."
*/
{
if (*name != '.')
return (FALSE);
return (TRUE);
return (FALSE);
}
/*
* Macros on fs_traverse flags.
*/
/*
* The traversing state that is pushed onto the stack.
* This include:
* - The end of the path of the current directory.
* - The position of the last component on it.
* - The read position in the directory.
* - The file handle of the directory.
* - The stat of the directory.
*/
typedef struct traverse_state {
char *ts_end;
char *ts_ent;
/*
* Statistics gathering structure.
*/
typedef struct traverse_statistics {
/*
* Global instance of statistics variable.
*/
typedef struct {
short fd_len;
typedef struct dent_arg {
char *da_buf;
int da_end;
int da_size;
} dent_arg_t;
dent_arg_t *darg);
/*
* Gather some directory entry information and return them
*/
static int
{
return (-1);
/* LINTED improper alignment */
if (countp)
(*countp)++;
return (0);
}
/*
* Creates a new traversing state based on the path passed to it.
*/
static traverse_state_t *
{
if (!tsp)
return (NULL);
return (tsp);
}
/*
* Create a file handle and get stats for the given path
*/
int
{
return (errno);
else
return (0);
}
/*
* Get directory entries info and return in the buffer. Cookie
* will keep the state of each call
*/
static int
{
char *p;
int len;
int rv;
if (*nbyte == 0) {
if (rv <= 0)
return (rv);
}
do {
/* LINTED improper alignment */
goto skip_entry;
rv = -1;
break;
}
goto skip_entry;
break;
} while (len);
return (rv);
}
/*
* Read the directory entries and return the information about
* each entry
*/
int
{
int rv;
return (errno);
rv = 0; /* skip this dir */
*el = 0;
} else {
if (rv == 0) {
} else {
*el = 0;
}
}
return (rv);
}
/*
* Traverse the file system in the post-order way. The description
* and example is in the header file.
*
* The callback function should return 0, on success and non-zero on
* failure. If the callback function returns non-zero return value,
* the traversing stops.
*/
int
{
return (-1);
}
/* set the default log function if it's not already set */
}
/* set the logical path to physical path if it's not already set */
}
return (-1);
}
if (rv != 0) {
return (rv);
}
return (rv);
}
sp = cstack_new();
if (!sp) {
return (-1);
}
if (!tsp) {
return (-1);
}
rv = 0;
next_dir = 1;
do {
if (next_dir) {
}
next_dir = 0;
do {
if (rv != 0) {
"Error %d on readdir(%s) pos %d",
if (STOP_ONERR(ftp))
break;
rv = SKIP_ENTRY;
continue;
}
/* done with this directory */
if (el == 0) {
break;
}
if (rootfs_dot_or_dotdot(nm)) {
continue;
}
if (STOP_ONLONG(ftp))
rv = ENAMETOOLONG;
continue;
}
/*
* Push the current directory on to the stack and
* dive into the entry found.
*/
break;
}
/*
* Concatenate the current entry with the
* current path. This will be the path of
* the new directory to be scanned.
*
* Note:
* sprintf(tsp->ts_end, "/%s", de->d_name);
* could be used here, but concatenating
* strings like this might be faster.
* The length of the new path has been
* checked above. So strcpy() can be
* safe and should not lead to a buffer
* over-run.
*/
if (!tsp) {
} else {
next_dir = 1;
}
break;
} else {
/*
* The entry is not a directory so the
* callback function must be called.
*/
"CALLBACK(%s/%s): %d",
if (rv != 0)
break;
}
} while (rv == 0);
/*
* A new directory must be processed, go to the start of
* the loop, open it and process it.
*/
if (next_dir)
continue;
if (rv == SKIP_ENTRY)
rv = 0; /* We should skip the current directory */
if (rv == 0) {
/*
* Remove the ent from the end of path and send it
* as an entry of the path.
*/
*lp = '\0';
break;
/*
* Does not need to free tsp here. It will be released
* later.
*/
}
}
} while (rv == 0);
/*
* For the 'ftp->ft_path' directory itself.
*/
if (rv == 0) {
}
/*
* Pop and free all the remaining entries on the stack.
*/
}
return (rv);
}
/*
* In one pass, read all the directory entries of the specified
* directory and call the callback function for non-directory
* entries.
*
* On return:
* 0: Lets the directory to be scanned for directory entries.
* < 0: Completely stops traversing.
* FST_SKIP: stops further scanning of the directory. Traversing
* will continue with the next directory in the hierarchy.
* SKIP_ENTRY: Failed to get the directory entries, so the caller
* should skip this entry.
*/
static int
{
int rv;
int fd;
rv = 0;
return (errno);
if (fd == -1) {
return (errno);
}
while (rv == 0) {
long i, n_entries;
n_entries = 0;
if (rv < 0) {
if (STOP_ONERR(ftp))
break;
/*
* We cannot read the directory entry, we should
* skip to the next directory.
*/
rv = SKIP_ENTRY;
continue;
} else {
/* Break at the end of directory */
if (rv > 0)
rv = 0;
else
break;
}
/* LINTED imporper alignment */
/* LINTED imporper alignment */
if (STOP_ONLONG(ftp))
rv = -ENAMETOOLONG;
continue;
}
/*
* The entry is not a directory so the callback
* function must be called.
*/
if (rv < 0)
break;
break;
}
}
}
}
return (rv);
}
/*
* Traverse the file system in the level-order way. The description
* and example is in the header file.
*/
int
{
return (-1);
}
/* set the default log function if it's not already set */
}
}
return (-1);
}
if (rv != 0) {
return (-1);
}
return (rv);
}
sp = cstack_new();
if (!sp) {
return (-1);
}
if (!tsp) {
return (-1);
}
return (-1);
}
/* call the callback function on the path itself */
if (rv < 0) {
goto end;
}
rv = 0;
goto end;
}
rv = 0;
next_dir = 1;
do {
if (next_dir) {
if (rv < 0) {
break;
}
/*
* If skipped by the callback function or
* error happened reading the information
*/
/*
* N.B. next_dir should be set to 0 as
* well. This prevents the infinite loop.
* If it's not set the same directory will
* be poped from the stack and will be
* scanned again.
*/
next_dir = 0;
rv = 0;
goto skip_dir;
}
/* re-start reading entries of the directory */
}
next_dir = 0;
do {
&est);
if (rv != 0) {
"Error %d on readdir(%s) pos %d",
if (STOP_ONERR(ftp))
break;
rv = SKIP_ENTRY;
continue;
}
/* done with this directory */
if (el == 0)
break;
if (rootfs_dot_or_dotdot(nm)) {
continue;
}
/*
* The long paths were already encountered
* when processing non-dir entries in.
* traverse_level_nondir.
* We don't increase fss_longpath_err
* counter for them again here.
*/
if (STOP_ONLONG(ftp))
rv = ENAMETOOLONG;
continue;
}
continue;
/*
* Call the callback function for the new
* directory found, then push the current
* directory on to the stack. Then dive
* into the entry found.
*/
if (rv < 0) {
break;
}
rv = 0;
continue;
}
/*
* Push the current directory on to the stack and
* dive into the entry found.
*/
} else {
if (!tsp)
else {
next_dir = 1;
}
}
break;
} while (rv == 0);
/*
* A new directory must be processed, go to the start of
* the loop, open it and process it.
*/
if (next_dir)
continue;
if (tsp) {
}
if (rv == SKIP_ENTRY)
rv = 0;
if (rv == 0) {
break;
}
} while (rv == 0);
/*
* Pop and free all the remaining entries on the stack.
*/
}
end:
return (rv);
}
/*
* filecopy - Copy a file
*
* Parameters:
* char *dest - Destination path
* char *src - Source path
*
* Returns:
* 0 - No errors
* #0 - Error occured
* -5 - source modified during copy
*
* Simplified version for Solaris
*/
int
{
char *buf = 0;
int file_copied = 0;
if (!buf)
return (-1);
if (src_fh == 0) {
return (-2);
}
return (-3);
}
return (-2);
}
while (bytes_to_copy) {
if (bytes_to_copy > BUFSIZE)
else
break;
bytes_to_copy -= nbytes;
}
if (bytes_to_copy > 0) {
return (-4);
}
return (-2);
}
if (!file_copied)
return (-5); /* source modified during copy */
else
return (0);
}