File es_posix.c¶
File List > cubrid > src > storage > es_posix.c
Go to the documentation of this file
/*
* Copyright 2008 Search Solution Corporation
* Copyright 2016 CUBRID Corporation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
/*
* es_posix.c - POSIX FS API for external storage supports (at server)
*/
#include "config.h"
#include <stdio.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <assert.h>
#if defined(WINDOWS)
#include <io.h>
#define S_ISDIR(m) ((m) & S_IFDIR)
typedef int mode_t;
#else
#include <unistd.h>
#include <sys/vfs.h>
#include <string.h>
#endif /* !WINDOWS */
#include "porting.h"
#include "thread_compat.hpp"
#include "error_manager.h"
#include "system_parameter.h"
#include "error_code.h"
#include "es_posix.h"
#if defined (SERVER_MODE)
#include "thread_entry.hpp"
#include "thread_manager.hpp" // for thread_get_thread_entry_info
#endif // SERVER_MODE
// XXX: SHOULD BE THE LAST INCLUDE HEADER
#include "memory_wrapper.hpp"
#define ES_POSIX_COPY_BUFSIZE (4096 * 4) /* 16K */
#if defined (SA_MODE) || defined (SERVER_MODE)
/* es_posix_base_dir - */
char es_base_dir[PATH_MAX] = { 0 };
static void es_get_unique_name (char *dirname1, char *dirname2, const char *metaname, char *filename);
static void es_rename_path (const char *src, char *tgt, char *metaname);
static int es_abs_open (const char *abs_path, int flags);
static int es_abs_open (const char *abs_path, int flags, mode_t mode);
static int es_make_abs_path (char *abs_path, const char *src_path);
static int es_os_rename_file_abs (const char *src, const char *dst);
/*
* es_posix_get_unique_name - make unique path string for external file
*
* return: none
* dirname1(out): first level directory name which is generated
* dirname2(out): second level directory name which is generated
* filename(out): generated file name
*/
static void
es_get_unique_name (char *dirname1, char *dirname2, const char *metaname, char *filename)
{
UINT64 unum;
int hashval;
int r;
#if defined(SERVER_MODE)
THREAD_ENTRY *thread_p;
thread_p = thread_get_thread_entry_info ();
assert (thread_p != NULL);
r = rand_r (&thread_p->rand_seed);
#else
r = rand ();
#endif
/* defensive, we don't want minus in filename */
r = r < 0 ? r * (-1) : r;
/* get unique numbers */
unum = es_get_unique_num ();
/* make a file name & a dir name */
snprintf (filename, NAME_MAX, "%s.%020llu_%04d", metaname, (unsigned long long) unum, r % 10000);
hashval = es_name_hash_func (ES_POSIX_HASH1, filename);
snprintf (dirname1, NAME_MAX, "ces_%03d", hashval);
hashval = es_name_hash_func (ES_POSIX_HASH2, filename);
snprintf (dirname2, NAME_MAX, "ces_%03d", hashval);
}
/*
* es_posix_make_dirs -
*
* return: error code, ER_ES_GENERAL or NO_ERROR
* dirname1(in): first level directory name
* dirname2(in): second level directory name
*/
int
es_make_dirs (const char *dirname1, const char *dirname2)
{
char dirbuf[PATH_MAX];
int ret;
#if defined (CUBRID_OWFS_POSIX_TWO_DEPTH_DIRECTORY)
retry:
if (snprintf (dirbuf, PATH_MAX - 1, "%s%c%s%c%s", es_base_dir, PATH_SEPARATOR, dirname1, PATH_SEPARATOR, dirname2)
< 0)
{
assert (false);
return ER_ES_INVALID_PATH;
}
ret = mkdir (dirbuf, 0755);
if (ret < 0 && errno == ENOENT)
{
n = snprintf (dirbuf, PATH_MAX - 1, "%s%c%s", es_base_dir, PATH_SEPARATOR, dirname1);
ret = mkdir (dirbuf, 0755);
if (ret == 0 || errno == EEXIST)
{
goto retry;
}
}
#else
if (snprintf (dirbuf, PATH_MAX - 1, "%s%c%s", es_base_dir, PATH_SEPARATOR, dirname1) < 0)
{
assert (false);
return ER_ES_INVALID_PATH;
}
ret = mkdir (dirbuf, 0744);
#endif
if (ret < 0 && errno != EEXIST)
{
er_set_with_oserror (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_ES_GENERAL, 2, "POSIX", dirbuf);
return ER_ES_GENERAL;
}
return NO_ERROR;
}
/*
* es_rename_path -
*
* return:
* src(in): source path to be converted
* metaname(in): new file name hint replacing a part of the src
* tgt(out): target path
*/
static void
es_rename_path (const char *src, char *tgt, char *metaname)
{
const char *s;
char *t;
assert (metaname != NULL);
/*
* src: /.../ces_000/ces_tmp.123456789
* ^
* s
*/
s = strrchr (src, PATH_SEPARATOR);
assert (s != NULL);
strcpy (tgt, src);
if (s == NULL)
{
return;
}
/*
* tgt: /.../ces_000/ces_tmp.123456789
* ^
* t
*/
t = tgt + (s - src) + 1;
/*
* tgt: /.../ces_000/ces_tmp.123456789
* ^
* s
*/
s = strchr (s, '.');
assert (s != NULL);
if (s == NULL)
{
return;
}
sprintf (t, "%s%s", metaname, s);
}
/*
* es_abs_open -
*
* return: return code of file open
* path(in): file path for open, relative or absolute
* if relative, (lob_base_path) + path will be opened
*/
static int
es_abs_open (const char *path, int flags)
{
const char *abs_path = path;
char path_buf[PATH_MAX];
int ret = NO_ERROR;
if ((ret = es_make_abs_path (path_buf, path)) < 0)
{
return ret;
}
if (ret > 0)
{
abs_path = path_buf;
}
return open (abs_path, flags);
}
static int
es_abs_open (const char *path, int flags, mode_t mode)
{
const char *abs_path = path;
char path_buf[PATH_MAX];
int ret = NO_ERROR;
if ((ret = es_make_abs_path (path_buf, path)) < 0)
{
return ret;
}
if (ret > 0)
{
abs_path = path_buf;
}
return open (abs_path, flags, mode);
}
/*
* es_make_abs_path -
*
* return: return code, 0: already absolute path
* path(in): file path for open, relative or absolute
* if relative, (lob_base_path) + path will be opened
*/
static int
es_make_abs_path (char *dst, const char *src)
{
int ret = 0;
if ((IS_ABS_PATH (src)) == false)
{
ret = snprintf (dst, PATH_MAX, "%s%c%s", es_base_dir, PATH_SEPARATOR, src);
}
return ret;
}
#endif /* SA_MODE || SERVER_MODE */
/*
* es_posix_init - initialize posix module
* set the directory for external files
*
* return: error code, ER_ES_GENERAL or NO_ERRROR
* basedir(in): base directory path
*/
int
es_posix_init (const char *base_path)
{
#if defined(SA_MODE) || defined(SERVER_MODE)
int ret;
struct stat sbuf;
ret = stat (base_path, &sbuf);
if (ret != 0 || !S_ISDIR (sbuf.st_mode))
{
/* failed to open base dir */
er_set_with_oserror (ER_NOTIFICATION_SEVERITY, ARG_FILE_LINE, ER_ES_GENERAL, 2, "POSIX", base_path);
return ER_ES_GENERAL;
}
/* set base dir */
strlcpy (es_base_dir, base_path, PATH_MAX);
return NO_ERROR;
#else /* SA_MODE || SERVER_MODE */
return NO_ERROR;
#endif /* CS_MODE */
}
/*
* es_posix_final - finalize posix module
*
* return: none
*/
void
es_posix_final (void)
{
return;
}
#if defined(SA_MODE) || defined(SERVER_MODE)
/*
* xes_posix_create_file - create a new external file with auto generated name
*
* return: error code, ER_ES_GENERAL or NO_ERRROR
* new_path(out): file path newly created
*/
int
xes_posix_create_file (char *new_path)
{
int fd;
int ret, n;
char dirname1[NAME_MAX], dirname2[NAME_MAX], filename[NAME_MAX];
retry:
es_get_unique_name (dirname1, dirname2, "ces_temp", filename);
#if defined (CUBRID_OWFS_POSIX_TWO_DEPTH_DIRECTORY)
n = snprintf (new_path, PATH_MAX - 1, "%s%c%s%c%s%c%s", es_base_dir, PATH_SEPARATOR, dirname1, PATH_SEPARATOR,
dirname2, PATH_SEPARATOR, filename);
#else
/* default */
n = snprintf (new_path, PATH_MAX - 1, "%s%c%s", dirname1, PATH_SEPARATOR, filename);
#endif
if (n < 0)
{
assert (false);
return ER_ES_INVALID_PATH;
}
es_log ("xes_posix_create_file(): %s\n", new_path);
#if defined (WINDOWS)
fd = es_abs_open (new_path, O_WRONLY | O_CREAT | O_EXCL | O_BINARY, S_IRWXU);
#else /* WINDOWS */
fd = es_abs_open (new_path, O_WRONLY | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH | O_LARGEFILE);
#endif /* !WINDOWS */
if (fd < 0)
{
if (errno == ENOENT)
{
ret = es_make_dirs (dirname1, dirname2);
if (ret != NO_ERROR)
{
return ret;
}
#if defined (WINDOWS)
fd = es_abs_open (new_path, O_WRONLY | O_CREAT | O_EXCL | O_BINARY, S_IRWXU);
#else /* WINDOWs */
fd = es_abs_open (new_path, O_WRONLY | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH | O_LARGEFILE);
#endif /* !WINDOWS */
}
}
if (fd < 0)
{
if (errno == EEXIST)
{
goto retry;
}
er_set_with_oserror (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_ES_GENERAL, 2, "POSIX", new_path);
return ER_ES_GENERAL;
}
close (fd);
return NO_ERROR;
}
/*
* xes_posix_write_file - write to the external file
*
* return: error code, ER_ES_GENERAL or NO_ERRROR
* path(in): file path
*/
ssize_t
xes_posix_write_file (const char *path, const void *buf, size_t count, off_t offset)
{
struct stat pstat;
int fd;
ssize_t nbytes;
size_t total = 0;
const char *abs_path = path;
char path_buf[PATH_MAX];
if (es_make_abs_path (path_buf, path) > 0)
{
abs_path = path_buf;
}
es_log ("xes_posix_write_file(%s, count %d offset %ld)\n", abs_path, count, offset);
/*
* TODO: This block of codes prevents partial update or writing at advanced
* position or something like that.
* This restriction is introduced due to OwFS's capability.
* We need to reconsider about this specification.
*/
if (stat (abs_path, &pstat) < 0)
{
er_set_with_oserror (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_ES_GENERAL, 2, "POSIX", abs_path);
return ER_ES_GENERAL;
}
if (offset != pstat.st_size)
{
char buf[PATH_MAX];
snprintf (buf, PATH_MAX, "offset error %s", path);
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_ES_GENERAL, 2, "POSIX", buf);
return ER_ES_GENERAL;
}
#if defined (WINDOWS)
fd = es_abs_open (abs_path, O_WRONLY | O_APPEND | O_BINARY, S_IRWXU);
#else /* WINDOWs */
fd = es_abs_open (abs_path, O_WRONLY | O_APPEND, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH | O_LARGEFILE);
#endif /* !WINDOWS */
if (fd < 0)
{
er_set_with_oserror (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_ES_GENERAL, 2, "POSIX", path);
return ER_ES_GENERAL;
}
while (count > 0)
{
if (lseek (fd, offset, SEEK_SET) != offset)
{
er_set_with_oserror (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_ES_GENERAL, 2, "POSIX", path);
close (fd);
return ER_ES_GENERAL;
}
nbytes = write (fd, buf, (unsigned) count);
if (nbytes <= 0)
{
switch (errno)
{
case EINTR:
case EAGAIN:
continue;
default:
{
er_set_with_oserror (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_ES_GENERAL, 2, "POSIX", path);
close (fd);
return ER_ES_GENERAL;
}
}
}
offset += nbytes;
count -= nbytes;
buf = (char *) buf + nbytes;
total += nbytes;
}
close (fd);
return total;
}
/*
* xes_posix_read_file - read from the external file
*
* return: error code, ER_ES_GENERAL or NO_ERRROR
* path(in): file path
*/
ssize_t
xes_posix_read_file (const char *path, void *buf, size_t count, off_t offset)
{
int fd;
ssize_t nbytes;
size_t total = 0;
es_log ("xes_posix_read_file(%s, count %d offset %ld)\n", path, count, offset);
#if defined (WINDOWS)
fd = es_abs_open (path, O_RDONLY | O_BINARY);
#else /* WINDOWS */
fd = es_abs_open (path, O_RDONLY | O_LARGEFILE);
#endif /* !WINDOWS */
if (fd < 0)
{
if (errno == ENOENT)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_ES_FILE_NOT_FOUND, 1, path);
return ER_ES_FILE_NOT_FOUND;
}
else
{
er_set_with_oserror (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_ES_GENERAL, 2, "POSIX", path);
return ER_ES_GENERAL;
}
}
while (count > 0)
{
if (lseek (fd, offset, SEEK_SET) != offset)
{
er_set_with_oserror (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_ES_GENERAL, 2, "POSIX", path);
close (fd);
return ER_ES_GENERAL;
}
nbytes = read (fd, buf, (unsigned) count);
if (nbytes < 0)
{
switch (errno)
{
case EINTR:
case EAGAIN:
continue;
default:
{
er_set_with_oserror (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_ES_GENERAL, 2, "POSIX", path);
close (fd);
return ER_ES_GENERAL;
}
}
}
if (nbytes == 0)
{
break;
}
offset += nbytes;
count -= nbytes;
buf = (char *) buf + nbytes;
total += nbytes;
}
close (fd);
return total;
}
/*
* xes_posix_delete_file - delete the external file
*
* return: error code, ER_ES_GENERAL or NO_ERRROR
* path(in): file path
*/
int
xes_posix_delete_file (const char *path)
{
int ret;
const char *abs_path = path;
char buf[PATH_MAX];
if (es_make_abs_path (buf, path) > 0)
{
abs_path = buf;
}
es_log ("xes_posix_delete_file(%s)\n", abs_path);
ret = unlink (abs_path);
if (ret < 0)
{
er_set_with_oserror (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_ES_GENERAL, 2, "POSIX", abs_path);
return ER_ES_GENERAL;
}
return NO_ERROR;
}
/*
* xes_posix_copy_file - copy the external file to new one
*
* return: error code, ER_ES_GENERAL or NO_ERRROR
* src_path(in): file path to be copied
* new_path(out): file path newly created
*/
int
xes_posix_copy_file (const char *src_path, char *metaname, char *new_path)
{
int rd_fd, wr_fd, n;
ssize_t ret;
char dirname1[NAME_MAX], dirname2[NAME_MAX], filename[NAME_MAX];
char buf[ES_POSIX_COPY_BUFSIZE];
/* open a source file */
#if defined (WINDOWS)
rd_fd = es_abs_open (src_path, O_RDONLY | O_BINARY);
#else /* WINDOWS */
rd_fd = es_abs_open (src_path, O_RDONLY | O_LARGEFILE);
#endif /* !WINDOWS */
if (rd_fd < 0)
{
er_set_with_oserror (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_ES_GENERAL, 2, "POSIX", src_path);
return ER_ES_GENERAL;
}
retry:
/* create a target file */
es_get_unique_name (dirname1, dirname2, metaname, filename);
#if defined (CUBRID_OWFS_POSIX_TWO_DEPTH_DIRECTORY)
n = snprintf (new_path, PATH_MAX - 1, "%s%c%s%c%s%c%s", es_base_dir, PATH_SEPARATOR, dirname1, PATH_SEPARATOR,
dirname2, PATH_SEPARATOR, filename);
#else
/* default */
n = snprintf (new_path, PATH_MAX - 1, "%s%c%s", dirname1, PATH_SEPARATOR, filename);
#endif
if (n < 0)
{
close (rd_fd);
assert (false);
return ER_ES_INVALID_PATH;
}
es_log ("xes_posix_copy_file(%s, %s): %s\n", src_path, metaname, new_path);
#if defined (WINDOWS)
wr_fd = es_abs_open (new_path, O_WRONLY | O_CREAT | O_EXCL | O_BINARY, S_IRWXU);
#else /* WINDOWS */
wr_fd = es_abs_open (new_path, O_WRONLY | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH | O_LARGEFILE);
#endif /* !WINDOWS */
if (wr_fd < 0)
{
if (errno == ENOENT)
{
ret = es_make_dirs (dirname1, dirname2);
if (ret != NO_ERROR)
{
close (rd_fd);
return ER_ES_GENERAL;
}
#if defined (WINDOWS)
wr_fd = es_abs_open (new_path, O_WRONLY | O_CREAT | O_EXCL | O_BINARY, S_IRWXU);
#else /* WINDOWS */
wr_fd =
es_abs_open (new_path, O_WRONLY | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH | O_LARGEFILE);
#endif /* !WINDOWS */
}
}
if (wr_fd < 0)
{
if (errno == EEXIST)
{
goto retry;
}
er_set_with_oserror (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_ES_GENERAL, 2, "POSIX", new_path);
close (rd_fd);
return ER_ES_GENERAL;
}
/* copy data */
do
{
ret = read (rd_fd, buf, ES_POSIX_COPY_BUFSIZE);
if (ret == 0)
{
break; /* end of file */
}
else if (ret < 0)
{
er_set_with_oserror (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_ES_GENERAL, 2, "POSIX", src_path);
break;
}
ret = write (wr_fd, buf, (unsigned) ret);
if (ret <= 0)
{
er_set_with_oserror (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_ES_GENERAL, 2, "POSIX", new_path);
break;
}
}
while (ret > 0);
close (rd_fd);
close (wr_fd);
return (ret < 0) ? ER_ES_GENERAL : NO_ERROR;
}
/*
* xes_posix_copy_file_with_prefix - Similar to xes_posix_copy_file(), but handles only the ES_POSIX type and performs file copy
while adding a prefix to the destination path.
*
* return: error code
* src_path(in): path of the original source file
* metaname(in) : meta name combined with in_uri
* prefix(in): prefix that will be added to the destination path when copying
* new_path(out): new path of the copied file
*/
int
xes_posix_copy_file_with_prefix (const char *src_path, char *metaname, const char *prefix, char *new_path)
{
int rd_fd, wr_fd, n = 0;
ssize_t ret;
char dirname1[NAME_MAX], dirname2[NAME_MAX], filename[NAME_MAX];
char buf[ES_POSIX_COPY_BUFSIZE];
char *p;
/* Check the existence of the source file by trying to open it */
rd_fd = es_abs_open (src_path, O_RDONLY | O_LARGEFILE);
if (rd_fd < 0)
{
er_set_with_oserror (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_ES_GENERAL, 2, "POSIX", src_path);
return ER_ES_GENERAL;
}
retry:
/* create a target file */
es_get_unique_name (dirname1, dirname2, metaname, filename);
n = snprintf (new_path, PATH_MAX - 1, "%s%c%s%c%s", prefix, PATH_SEPARATOR, dirname1, PATH_SEPARATOR, filename);
if (n < 0 || n >= PATH_MAX - 1)
{
close (rd_fd);
return ER_ES_INVALID_PATH;
}
es_log ("xes_posix_copy_file_with_prefix(%s, %s): %s\n", src_path, metaname, new_path);
/* check file existence */
wr_fd = es_abs_open (new_path, O_WRONLY | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH | O_LARGEFILE);
if (wr_fd < 0)
{
if (errno == ENOENT)
{
p = strrchr (new_path, PATH_SEPARATOR);
if (p != NULL)
{
*p = '\0'; /* Temporarily truncate the path to extract the directory portion */
}
else
{
close (rd_fd);
return ER_ES_GENERAL;
}
ret = es_make_dirs (new_path, dirname2);
if (ret != NO_ERROR)
{
close (rd_fd);
er_set_with_oserror (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_ES_GENERAL, 2, "POSIX", src_path);
return ER_ES_GENERAL;
}
*p = PATH_SEPARATOR;
wr_fd =
es_abs_open (new_path, O_WRONLY | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH | O_LARGEFILE);
}
}
if (wr_fd < 0)
{
if (errno == EEXIST)
{
goto retry;
}
close (rd_fd);
er_set_with_oserror (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_ES_GENERAL, 2, "POSIX", new_path);
return ER_ES_GENERAL;
}
/* copy data */
do
{
ret = read (rd_fd, buf, ES_POSIX_COPY_BUFSIZE);
if (ret == 0)
{
break; /* end of file */
}
else if (ret < 0)
{
er_set_with_oserror (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_ES_GENERAL, 2, "POSIX", src_path);
break;
}
ret = write (wr_fd, buf, (unsigned) ret);
if (ret <= 0)
{
er_set_with_oserror (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_ES_GENERAL, 2, "POSIX", new_path);
break;
}
}
while (ret > 0);
close (rd_fd);
close (wr_fd);
return (ret < 0) ? ER_ES_GENERAL : NO_ERROR;
}
/*
* xes_posix_rename_file - convert a locator & file path according to the metaname
*
* return: error code, ER_ES_GENERAL or NO_ERRROR
* src_path(in): file path to rename
* metaname(in) : meta name combined with src_path
* new_path(out): new file path
*/
int
xes_posix_rename_file (const char *src_path, const char *metaname, char *new_path)
{
int ret;
es_rename_path ((char *) src_path, new_path, (char *) metaname);
es_log ("xes_posix_rename_file(%s, %s): %s\n", src_path, metaname, new_path);
ret = es_os_rename_file_abs (src_path, new_path);
return (ret < 0) ? ER_ES_GENERAL : NO_ERROR;
}
/*
* xes_posix_move_file_with_prefix - Moves a LOB file from the source path to a destination directory defined by the prefix.
*
* return: error code
* src_path(in): Source file path
* metaname(in) : Metadata used for the new file name
* prefix(in) : prefix to be added to the destination path when moving the file
* new_path(out): Resulting path of the moved file
*/
int
xes_posix_move_file_with_prefix (const char *src_path, const char *metaname, const char *prefix, char *new_path)
{
ssize_t ret;
char dirname1[NAME_MAX], dirname2[NAME_MAX], filename[NAME_MAX];
char *p;
/* Create a target file */
es_get_unique_name (dirname1, dirname2, metaname, filename);
ret = snprintf (new_path, PATH_MAX, "%s%c%s%c%s", prefix, PATH_SEPARATOR, dirname1, PATH_SEPARATOR, filename);
if (ret < 0 || ret >= PATH_MAX)
{
er_set_with_oserror (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_ES_GENERAL, 2, "POSIX", new_path);
return ER_ES_INVALID_PATH;
}
es_log ("xes_posix_move_file_with_prefix(%s, %s): %s\n", src_path, metaname, new_path);
p = strrchr (new_path, PATH_SEPARATOR);
if (p != NULL)
{
*p = '\0'; /* Temporarily truncate the path to extract the directory portion */
}
else
{
return ER_ES_GENERAL;
}
/* Try create directory */
ret = es_make_dirs (new_path, dirname2);
*p = PATH_SEPARATOR;
if (ret != NO_ERROR)
{
er_set_with_oserror (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_ES_GENERAL, 2, "POSIX", new_path);
return ER_ES_GENERAL;
}
ret = es_os_rename_file_abs (src_path, new_path);
if (ret != NO_ERROR)
{
er_set_with_oserror (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_ES_GENERAL, 2, "POSIX", src_path);
return ER_ES_GENERAL;
}
return NO_ERROR;
}
static int
es_os_rename_file_abs (const char *src, const char *dst)
{
const char *abs_dst_path = dst, *abs_src_path = src;
char dst_buf[PATH_MAX], src_buf[PATH_MAX];
if (es_make_abs_path (src_buf, src) > 0)
{
abs_src_path = src_buf;
}
if (es_make_abs_path (dst_buf, dst) > 0)
{
abs_dst_path = dst_buf;
}
return os_rename_file (abs_src_path, abs_dst_path);
}
/*
* xes_posix_get_file_size - get the size of the external file
*
* return: file size, or ER_ES_GENERAL
* path(in): file path
*/
off_t
xes_posix_get_file_size (const char *path)
{
int ret;
struct stat pstat;
const char *abs_path = path;
char buf[PATH_MAX];
if (es_make_abs_path (buf, path) > 0)
{
abs_path = buf;
}
es_log ("xes_posix_get_file_size(%s)\n", abs_path);
ret = stat (abs_path, &pstat);
if (ret < 0)
{
er_set_with_oserror (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_ES_GENERAL, 2, "POSIX", abs_path);
return -1;
}
return pstat.st_size;
}
#endif /* SA_MODE || SERVER_MODE */
/*
* es_local_read_file - read from the local file
*
* return: error code, ER_ES_GENERAL or NO_ERRROR
* path(in): file path
*/
int
es_local_read_file (const char *path, void *buf, size_t count, off_t offset)
{
int fd;
ssize_t nbytes;
size_t total = 0;
es_log ("es_local_read_file(%s, count %d offset %ld)\n", path, count, offset);
#if defined (WINDOWS)
fd = open (path, O_RDONLY | O_BINARY);
#else /* WINDOWS */
fd = open (path, O_RDONLY | O_LARGEFILE);
#endif /* !WINDOWS */
if (fd < 0)
{
er_set_with_oserror (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_ES_GENERAL, 2, "LOCAL", path);
return ER_ES_GENERAL;
}
while (count > 0)
{
if (lseek (fd, offset, SEEK_SET) != offset)
{
er_set_with_oserror (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_ES_GENERAL, 2, "LOCAL", path);
close (fd);
return ER_ES_GENERAL;
}
nbytes = read (fd, buf, (unsigned) count);
if (nbytes < 0)
{
switch (errno)
{
case EINTR:
case EAGAIN:
continue;
default:
{
er_set_with_oserror (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_ES_GENERAL, 2, "LOCAL", path);
close (fd);
return ER_ES_GENERAL;
}
}
}
if (nbytes == 0)
{
break;
}
offset += nbytes;
count -= nbytes;
buf = (char *) buf + nbytes;
total += nbytes;
}
close (fd);
return (int) total;
}
/*
* es_local_get_file_size - get the size of the external file
*
* return: file size, or ER_ES_GENERAL
* path(in): file path
*/
off_t
es_local_get_file_size (const char *path)
{
int ret;
struct stat pstat;
es_log ("es_local_get_file_size(%s)\n", path);
ret = stat (path, &pstat);
if (ret < 0)
{
er_set_with_oserror (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_ES_GENERAL, 2, "LOCAL", path);
return -1;
}
return pstat.st_size;
}