CUBRID Engine  latest
es_posix.c
Go to the documentation of this file.
1 /*
2  * Copyright 2008 Search Solution Corporation
3  * Copyright 2016 CUBRID Corporation
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  */
18 
19 /*
20  * es_posix.c - POSIX FS API for external storage supports (at server)
21  */
22 
23 #include "config.h"
24 
25 #include <stdio.h>
26 #include <errno.h>
27 #include <fcntl.h>
28 #include <sys/types.h>
29 #include <sys/stat.h>
30 #include <assert.h>
31 #if defined(WINDOWS)
32 #include <io.h>
33 #define S_ISDIR(m) ((m) & S_IFDIR)
34 #else
35 #include <unistd.h>
36 #include <sys/vfs.h>
37 #include <string.h>
38 #endif /* !WINDOWS */
39 
40 #include "porting.h"
41 #include "thread_compat.hpp"
42 #include "error_manager.h"
43 #include "system_parameter.h"
44 #include "error_code.h"
45 #include "es_posix.h"
46 #if defined (SERVER_MODE)
47 #include "thread_entry.hpp"
48 #include "thread_manager.hpp" // for thread_get_thread_entry_info
49 #endif // SERVER_MODE
50 
51 #if defined (SA_MODE) || defined (SERVER_MODE)
52 /* es_posix_base_dir - */
53 static char es_base_dir[PATH_MAX];
54 
55 static void es_get_unique_name (char *dirname1, char *dirname2, const char *metaname, char *filename);
56 static int es_make_dirs (const char *dirname1, const char *dirname2);
57 static void es_rename_path (char *src, char *tgt, char *metaname);
58 
59 /*
60  * es_posix_get_unique_name - make unique path string for external file
61  *
62  * return: none
63  * dirname1(out): first level directory name which is generated
64  * dirname2(out): second level directory name which is generated
65  * filename(out): generated file name
66  */
67 static void
68 es_get_unique_name (char *dirname1, char *dirname2, const char *metaname, char *filename)
69 {
70  UINT64 unum;
71  int hashval;
72  int r;
73 
74 #if defined(SERVER_MODE)
75  THREAD_ENTRY *thread_p;
76 
77  thread_p = thread_get_thread_entry_info ();
78  assert (thread_p != NULL);
79 
80  r = rand_r (&thread_p->rand_seed);
81 #else
82  r = rand ();
83 #endif
84 
85  /* get unique numbers */
86  unum = es_get_unique_num ();
87 
88  /* make a file name & a dir name */
89  snprintf (filename, NAME_MAX, "%s.%020llu_%04d", metaname, (unsigned long long) unum, r % 10000);
90 
91  hashval = es_name_hash_func (ES_POSIX_HASH1, filename);
92  snprintf (dirname1, NAME_MAX, "ces_%03d", hashval);
93 
94  hashval = es_name_hash_func (ES_POSIX_HASH2, filename);
95  snprintf (dirname2, NAME_MAX, "ces_%03d", hashval);
96 }
97 
98 /*
99  * es_posix_make_dirs -
100  *
101  * return: error code, ER_ES_GENERAL or NO_ERROR
102  * dirname1(in): first level directory name
103  * dirname2(in): second level directory name
104  */
105 static int
106 es_make_dirs (const char *dirname1, const char *dirname2)
107 {
108  char dirbuf[PATH_MAX];
109  int ret;
110 
111 #if defined (CUBRID_OWFS_POSIX_TWO_DEPTH_DIRECTORY)
112 retry:
113  if (snprintf (dirbuf, PATH_MAX - 1, "%s%c%s%c%s", es_base_dir, PATH_SEPARATOR, dirname1, PATH_SEPARATOR, dirname2)
114  < 0)
115  {
116  assert (false);
117  return ER_ES_INVALID_PATH;
118  }
119  ret = mkdir (dirbuf, 0755);
120  if (ret < 0 && errno == ENOENT)
121  {
122  n = snprintf (dirbuf, PATH_MAX - 1, "%s%c%s", es_base_dir, PATH_SEPARATOR, dirname1);
123  ret = mkdir (dirbuf, 0755);
124  if (ret == 0 || errno == EEXIST)
125  {
126  goto retry;
127  }
128  }
129 #else
130  if (snprintf (dirbuf, PATH_MAX - 1, "%s%c%s", es_base_dir, PATH_SEPARATOR, dirname1) < 0)
131  {
132  assert (false);
133  return ER_ES_INVALID_PATH;
134  }
135  ret = mkdir (dirbuf, 0755);
136 #endif
137 
138  if (ret < 0 && errno != EEXIST)
139  {
141  return ER_ES_GENERAL;
142  }
143  return NO_ERROR;
144 }
145 
146 /*
147  * es_rename_path -
148  *
149  * return:
150  * src(in): source path to be converted
151  * metaname(in): new file name hint replacing a part of the src
152  * tgt(out): target path
153  */
154 static void
155 es_rename_path (char *src, char *tgt, char *metaname)
156 {
157  char *s, *t;
158 
159  assert (metaname != NULL);
160  /*
161  * src: /.../ces_000/ces_tmp.123456789
162  * ^
163  * s
164  */
165  s = strrchr (src, PATH_SEPARATOR);
166  assert (s != NULL);
167  strcpy (tgt, src);
168  if (s == NULL)
169  {
170  return;
171  }
172  /*
173  * tgt: /.../ces_000/ces_tmp.123456789
174  * ^
175  * t
176  */
177  t = tgt + (s - src) + 1;
178 
179  /*
180  * tgt: /.../ces_000/ces_tmp.123456789
181  * ^
182  * s
183  */
184  s = strchr (s, '.');
185  assert (s != NULL);
186  if (s == NULL)
187  {
188  return;
189  }
190 
191  sprintf (t, "%s%s", metaname, s);
192 }
193 #endif /* SA_MODE || SERVER_MODE */
194 
195 
196 /*
197  * es_posix_init - initialize posix module
198  * set the directory for external files
199  *
200  * return: error code, ER_ES_GENERAL or NO_ERRROR
201  * basedir(in): base directory path
202  */
203 int
204 es_posix_init (const char *base_path)
205 {
206 #if defined(SA_MODE) || defined(SERVER_MODE)
207  int ret;
208  struct stat sbuf;
209 
210  ret = stat (base_path, &sbuf);
211  if (ret != 0 || !S_ISDIR (sbuf.st_mode))
212  {
213  /* failed to open base dir */
215  return ER_ES_GENERAL;
216  }
217 
218  /* set base dir */
219  strlcpy (es_base_dir, base_path, PATH_MAX);
220  return NO_ERROR;
221 #else /* SA_MODE || SERVER_MODE */
222  return NO_ERROR;
223 #endif /* CS_MODE */
224 }
225 
226 /*
227  * es_posix_final - finalize posix module
228  *
229  * return: none
230  */
231 void
233 {
234  return;
235 }
236 
237 #if defined(SA_MODE) || defined(SERVER_MODE)
238 /*
239  * xes_posix_create_file - create a new external file with auto generated name
240  *
241  * return: error code, ER_ES_GENERAL or NO_ERRROR
242  * new_path(out): file path newly created
243  */
244 int
245 xes_posix_create_file (char *new_path)
246 {
247  int fd;
248  int ret, n;
249  char dirname1[NAME_MAX], dirname2[NAME_MAX], filename[NAME_MAX];
250 
251 retry:
252  es_get_unique_name (dirname1, dirname2, "ces_temp", filename);
253 #if defined (CUBRID_OWFS_POSIX_TWO_DEPTH_DIRECTORY)
254  n = snprintf (new_path, PATH_MAX - 1, "%s%c%s%c%s%c%s", es_base_dir, PATH_SEPARATOR, dirname1, PATH_SEPARATOR,
255  dirname2, PATH_SEPARATOR, filename);
256 #else
257  /* default */
258  n = snprintf (new_path, PATH_MAX - 1, "%s%c%s%c%s", es_base_dir, PATH_SEPARATOR, dirname1, PATH_SEPARATOR, filename);
259 #endif
260  if (n < 0)
261  {
262  assert (false);
263  return ER_ES_INVALID_PATH;
264  }
265 
266  es_log ("xes_posix_create_file(): %s\n", new_path);
267 
268 #if defined (WINDOWS)
269  fd = open (new_path, O_WRONLY | O_CREAT | O_EXCL | O_BINARY, S_IRWXU);
270 #else /* WINDOWS */
271  fd = open (new_path, O_WRONLY | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH | O_LARGEFILE);
272 #endif /* !WINDOWS */
273  if (fd < 0)
274  {
275  if (errno == ENOENT)
276  {
277  ret = es_make_dirs (dirname1, dirname2);
278  if (ret != NO_ERROR)
279  {
280  return ret;
281  }
282 #if defined (WINDOWS)
283  fd = open (new_path, O_WRONLY | O_CREAT | O_EXCL | O_BINARY, S_IRWXU);
284 #else /* WINDOWs */
285  fd = open (new_path, O_WRONLY | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH | O_LARGEFILE);
286 #endif /* !WINDOWS */
287  }
288  }
289 
290  if (fd < 0)
291  {
292  if (errno == EEXIST)
293  {
294  goto retry;
295  }
297  return ER_ES_GENERAL;
298  }
299  close (fd);
300  return NO_ERROR;
301 }
302 
303 /*
304  * xes_posix_write_file - write to the external file
305  *
306  * return: error code, ER_ES_GENERAL or NO_ERRROR
307  * path(in): file path
308  */
309 ssize_t
310 xes_posix_write_file (const char *path, const void *buf, size_t count, off_t offset)
311 {
312  struct stat pstat;
313  int fd;
314  ssize_t nbytes;
315  size_t total = 0;
316 
317  es_log ("xes_posix_write_file(%s, count %d offset %ld)\n", path, count, offset);
318 
319  /*
320  * TODO: This block of codes prevents partial update or writing at advanced
321  * position or something like that.
322  * This restriction is introduced due to OwFS's capability.
323  * We need to reconsider about this specification.
324  */
325  if (stat (path, &pstat) < 0)
326  {
328  return ER_ES_GENERAL;
329  }
330  if (offset != pstat.st_size)
331  {
332  char buf[PATH_MAX];
333  snprintf (buf, PATH_MAX, "offset error %s", path);
335  return ER_ES_GENERAL;
336  }
337 
338 #if defined (WINDOWS)
339  fd = open (path, O_WRONLY | O_APPEND | O_BINARY, S_IRWXU);
340 #else /* WINDOWs */
341  fd = open (path, O_WRONLY | O_APPEND, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH | O_LARGEFILE);
342 #endif /* !WINDOWS */
343  if (fd < 0)
344  {
346  return ER_ES_GENERAL;
347  }
348 
349  while (count > 0)
350  {
351  if (lseek (fd, offset, SEEK_SET) != offset)
352  {
354  close (fd);
355  return ER_ES_GENERAL;
356  }
357 
358  nbytes = write (fd, buf, (unsigned) count);
359  if (nbytes <= 0)
360  {
361  switch (errno)
362  {
363  case EINTR:
364  case EAGAIN:
365  continue;
366  default:
367  {
369  close (fd);
370  return ER_ES_GENERAL;
371  }
372  }
373  }
374 
375  offset += nbytes;
376  count -= nbytes;
377  buf = (char *) buf + nbytes;
378  total += nbytes;
379  }
380  close (fd);
381 
382  return total;
383 }
384 
385 /*
386  * xes_posix_read_file - read from the external file
387  *
388  * return: error code, ER_ES_GENERAL or NO_ERRROR
389  * path(in): file path
390  */
391 ssize_t
392 xes_posix_read_file (const char *path, void *buf, size_t count, off_t offset)
393 {
394  int fd;
395  ssize_t nbytes;
396  size_t total = 0;
397 
398  es_log ("xes_posix_read_file(%s, count %d offset %ld)\n", path, count, offset);
399 
400 #if defined (WINDOWS)
401  fd = open (path, O_RDONLY | O_BINARY);
402 #else /* WINDOWS */
403  fd = open (path, O_RDONLY | O_LARGEFILE);
404 #endif /* !WINDOWS */
405  if (fd < 0)
406  {
407  if (errno == ENOENT)
408  {
410  return ER_ES_FILE_NOT_FOUND;
411  }
412  else
413  {
415  return ER_ES_GENERAL;
416  }
417  }
418 
419  while (count > 0)
420  {
421  if (lseek (fd, offset, SEEK_SET) != offset)
422  {
424  close (fd);
425  return ER_ES_GENERAL;
426  }
427 
428  nbytes = read (fd, buf, (unsigned) count);
429  if (nbytes < 0)
430  {
431  switch (errno)
432  {
433  case EINTR:
434  case EAGAIN:
435  continue;
436  default:
437  {
439  close (fd);
440  return ER_ES_GENERAL;
441  }
442  }
443  }
444  if (nbytes == 0)
445  {
446  break;
447  }
448 
449  offset += nbytes;
450  count -= nbytes;
451  buf = (char *) buf + nbytes;
452  total += nbytes;
453  }
454  close (fd);
455 
456  return total;
457 }
458 
459 /*
460  * xes_posix_delete_file - delete the external file
461  *
462  * return: error code, ER_ES_GENERAL or NO_ERRROR
463  * path(in): file path
464  */
465 int
466 xes_posix_delete_file (const char *path)
467 {
468  int ret;
469 
470  es_log ("xes_posix_delete_file(%s)\n", path);
471 
472  ret = unlink (path);
473  if (ret < 0)
474  {
476  return ER_ES_GENERAL;
477  }
478 
479  return NO_ERROR;
480 }
481 
482 /*
483  * xes_posix_copy_file - copy the external file to new one
484  *
485  * return: error code, ER_ES_GENERAL or NO_ERRROR
486  * src_path(in): file path to be copied
487  * new_path(out): file path newly created
488  */
489 int
490 xes_posix_copy_file (const char *src_path, char *metaname, char *new_path)
491 {
492 #define ES_POSIX_COPY_BUFSIZE (4096 * 4) /* 16K */
493 
494  int rd_fd, wr_fd, n;
495  ssize_t ret;
496  char dirname1[NAME_MAX], dirname2[NAME_MAX], filename[NAME_MAX];
497  char buf[ES_POSIX_COPY_BUFSIZE];
498 
499  /* open a source file */
500 #if defined (WINDOWS)
501  rd_fd = open (src_path, O_RDONLY | O_BINARY);
502 #else /* WINDOWS */
503  rd_fd = open (src_path, O_RDONLY | O_LARGEFILE);
504 #endif /* !WINDOWS */
505  if (rd_fd < 0)
506  {
508  return ER_ES_GENERAL;
509  }
510 
511 retry:
512  /* create a target file */
513  es_get_unique_name (dirname1, dirname2, metaname, filename);
514 #if defined (CUBRID_OWFS_POSIX_TWO_DEPTH_DIRECTORY)
515  n = snprintf (new_path, PATH_MAX - 1, "%s%c%s%c%s%c%s", es_base_dir, PATH_SEPARATOR, dirname1, PATH_SEPARATOR,
516  dirname2, PATH_SEPARATOR, filename);
517 #else
518  /* default */
519  n = snprintf (new_path, PATH_MAX - 1, "%s%c%s%c%s", es_base_dir, PATH_SEPARATOR, dirname1, PATH_SEPARATOR, filename);
520 #endif
521  if (n < 0)
522  {
523  assert (false);
524  return ER_ES_INVALID_PATH;
525  }
526 
527  es_log ("xes_posix_copy_file(%s, %s): %s\n", src_path, metaname, new_path);
528 
529 #if defined (WINDOWS)
530  wr_fd = open (new_path, O_WRONLY | O_CREAT | O_EXCL | O_BINARY, S_IRWXU);
531 #else /* WINDOWS */
532  wr_fd = open (new_path, O_WRONLY | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH | O_LARGEFILE);
533 #endif /* !WINDOWS */
534  if (wr_fd < 0)
535  {
536  if (errno == ENOENT)
537  {
538  ret = es_make_dirs (dirname1, dirname2);
539  if (ret != NO_ERROR)
540  {
541  close (rd_fd);
542  return ER_ES_GENERAL;
543  }
544 #if defined (WINDOWS)
545  wr_fd = open (new_path, O_WRONLY | O_CREAT | O_EXCL | O_BINARY, S_IRWXU);
546 #else /* WINDOWS */
547  wr_fd = open (new_path, O_WRONLY | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH | O_LARGEFILE);
548 #endif /* !WINDOWS */
549  }
550  }
551 
552  if (wr_fd < 0)
553  {
554  if (errno == EEXIST)
555  {
556  goto retry;
557  }
559  close (rd_fd);
560  return ER_ES_GENERAL;
561  }
562 
563  /* copy data */
564  do
565  {
566  ret = read (rd_fd, buf, ES_POSIX_COPY_BUFSIZE);
567  if (ret == 0)
568  {
569  break; /* end of file */
570  }
571  else if (ret < 0)
572  {
574  break;
575  }
576 
577  ret = write (wr_fd, buf, (unsigned) ret);
578  if (ret <= 0)
579  {
581  break;
582  }
583  }
584  while (ret > 0);
585 
586  close (rd_fd);
587  close (wr_fd);
588 
589  return (ret < 0) ? ER_ES_GENERAL : NO_ERROR;
590 }
591 
592 /*
593  * es_posix_rename_file - convert a locator & file path according to the metaname
594  *
595  * return: error code, ER_ES_GENERAL or NO_ERRROR
596  * src_path(in): file path to rename
597  * metapath(in) : meta name combined with src_path
598  * new_path(out): new file path
599  */
600 int
601 xes_posix_rename_file (const char *src_path, const char *metaname, char *new_path)
602 {
603  int ret;
604 
605  es_rename_path ((char *) src_path, new_path, (char *) metaname);
606 
607  es_log ("xes_posix_rename_file(%s, %s): %s\n", src_path, metaname, new_path);
608 
609  ret = os_rename_file (src_path, new_path);
610 
611  return (ret < 0) ? ER_ES_GENERAL : NO_ERROR;
612 }
613 
614 
615 /*
616  * xes_posix_get_file_size - get the size of the external file
617  *
618  * return: file size, or ER_ES_GENERAL
619  * path(in): file path
620  */
621 off_t
622 xes_posix_get_file_size (const char *path)
623 {
624  int ret;
625  struct stat pstat;
626 
627  es_log ("xes_posix_get_file_size(%s)\n", path);
628 
629  ret = stat (path, &pstat);
630  if (ret < 0)
631  {
633  return -1;
634  }
635 
636  return pstat.st_size;
637 }
638 #endif /* SA_MODE || SERVER_MODE */
639 
640 /*
641  * es_local_read_file - read from the local file
642  *
643  * return: error code, ER_ES_GENERAL or NO_ERRROR
644  * path(in): file path
645  */
646 int
647 es_local_read_file (const char *path, void *buf, size_t count, off_t offset)
648 {
649  int fd;
650  ssize_t nbytes;
651  size_t total = 0;
652 
653  es_log ("es_local_read_file(%s, count %d offset %ld)\n", path, count, offset);
654 
655 #if defined (WINDOWS)
656  fd = open (path, O_RDONLY | O_BINARY);
657 #else /* WINDOWS */
658  fd = open (path, O_RDONLY | O_LARGEFILE);
659 #endif /* !WINDOWS */
660  if (fd < 0)
661  {
663  return ER_ES_GENERAL;
664  }
665 
666  while (count > 0)
667  {
668  if (lseek (fd, offset, SEEK_SET) != offset)
669  {
671  close (fd);
672  return ER_ES_GENERAL;
673  }
674 
675  nbytes = read (fd, buf, (unsigned) count);
676  if (nbytes < 0)
677  {
678  switch (errno)
679  {
680  case EINTR:
681  case EAGAIN:
682  continue;
683  default:
684  {
686  close (fd);
687  return ER_ES_GENERAL;
688  }
689  }
690  }
691  if (nbytes == 0)
692  {
693  break;
694  }
695 
696  offset += nbytes;
697  count -= nbytes;
698  buf = (char *) buf + nbytes;
699  total += nbytes;
700  }
701  close (fd);
702 
703  return (int) total;
704 }
705 
706 /*
707  * es_local_get_file_size - get the size of the external file
708  *
709  * return: file size, or ER_ES_GENERAL
710  * path(in): file path
711  */
712 off_t
713 es_local_get_file_size (const char *path)
714 {
715  int ret;
716  struct stat pstat;
717 
718  es_log ("es_local_get_file_size(%s)\n", path);
719 
720  ret = stat (path, &pstat);
721  if (ret < 0)
722  {
724  return -1;
725  }
726 
727  return pstat.st_size;
728 }
int os_rename_file(const char *src_path, const char *dest_path)
Definition: porting.c:1294
cubthread::entry * thread_get_thread_entry_info(void)
#define NO_ERROR
Definition: error_code.h:46
UINT64 es_get_unique_num(void)
Definition: es_common.c:102
#define ER_ES_INVALID_PATH
Definition: error_code.h:1272
int es_posix_init(const char *base_path)
Definition: es_posix.c:204
void THREAD_ENTRY
off_t es_local_get_file_size(const char *path)
Definition: es_posix.c:713
void er_set(int severity, const char *file_name, const int line_no, int err_id, int num_args,...)
#define assert(x)
#define NULL
Definition: freelistheap.h:34
int es_local_read_file(const char *path, void *buf, size_t count, off_t offset)
Definition: es_posix.c:647
void er_set_with_oserror(int severity, const char *file_name, const int line_no, int err_id, int num_args,...)
int count(int &result, const cub_regex_object &reg, const std::string &src, const int position, const INTL_CODESET codeset)
#define ARG_FILE_LINE
Definition: error_manager.h:44
size_t strlcpy(char *dst, const char *src, size_t siz)
Definition: porting.c:2584
void es_posix_final(void)
Definition: es_posix.c:232
#define ER_ES_GENERAL
Definition: error_code.h:1271
#define ES_POSIX_HASH2
Definition: es_posix.h:37
#define ER_ES_FILE_NOT_FOUND
Definition: error_code.h:1275
#define ES_POSIX_HASH1
Definition: es_posix.h:36
#define es_log(...)
Definition: es_common.h:45
#define PATH_SEPARATOR
Definition: porting.h:347
unsigned int es_name_hash_func(int size, const char *name)
Definition: es_common.c:92