/* objectstore_dummy.c
*
* Copyright (c) 1994-2008 Carnegie Mellon University. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The name "Carnegie Mellon University" must not be used to
* endorse or promote products derived from this software without
* prior written permission. For permission or any legal
* details, please contact
* Carnegie Mellon University
* Center for Technology Transfer and Enterprise Creation
* 4615 Forbes Avenue
* Suite 302
* Pittsburgh, PA 15213
* (412) 268-7393, fax: (412) 268-7395
* innovation@andrew.cmu.edu
*
* 4. Redistributions of any form whatsoever must retain the following
* acknowledgment:
* "This product includes software developed by Computing Services
* at Carnegie Mellon University (http://www.cmu.edu/computing/)."
*
* CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
* THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
* FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
* AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <stdio.h>
#include <dirent.h>
#include <stdlib.h>
#include <assert.h>
#include <errno.h>
#include <syslog.h>
#include "mailbox.h"
#include "mboxname.h"
#include "libconfig.h"
#include "xmalloc.h"
#include "util.h"
#include "objectstore.h"
#include "objectstore_db.h"
struct object_def
{
/* primary */
const char *namespace; // in this implementation this is the flat directory emulating the object storage
const char *user; // this is the container name.
const char *filename; // Name of blob
};
static const char *objectstore_get_object_filename(struct mailbox *mailbox __attribute__((unused)),
const struct index_record *record)
{
return message_guid_encode(&record->guid);
}
static struct object_def *objectstore_get_object_def(struct mailbox *mailbox,
const struct index_record *record)
{
static struct object_def obj_def ;
const char *namespace = config_getstring(IMAPOPT_OBJECT_STORAGE_DUMMY_SPOOL) ;
obj_def.namespace = namespace ;
obj_def.filename = objectstore_get_object_filename(mailbox, record) ;
obj_def.user = mboxname_to_userid(mailbox->name) ;
return &obj_def;
}
static const char *objectstore_container_path(struct mailbox *mailbox,
const struct index_record *record)
{
static char path[MAX_MAILBOX_PATH+1];
struct object_def *obj_def = NULL;
obj_def = objectstore_get_object_def (mailbox, record);
snprintf(path, sizeof(path), "%s/%s/%c%c", obj_def->namespace, obj_def->user, obj_def->filename[0], obj_def->filename[1]);
return path ;
}
static const char *objectstore_filename_in_container_path(struct mailbox *mailbox,
const struct index_record *record)
{
static char path[MAX_MAILBOX_PATH+1];
struct object_def *obj_def = NULL;
obj_def = objectstore_get_object_def (mailbox, record);
const char *container_path = objectstore_container_path(mailbox, record) ;
snprintf(path, sizeof(path), "%s/%s", container_path, obj_def->filename);
return path ;
}
static int is_directory_empty(char *dir_path)
{
int n = 0;
struct dirent *d;
DIR *dir = opendir(dir_path);
if (dir == NULL)
return 0 ;
while ((d = readdir(dir)) != NULL) {
if(++n > 2)
break;
}
closedir(dir);
if (n <= 2) // The directory is empty
return 1;
else
return 0;
}
int objectstore_put (struct mailbox *mailbox, const struct index_record *record, const char *fname)
{
struct object_def *obj_def = NULL;
int already = 0 ;
int rc = 0;
obj_def = objectstore_get_object_def (mailbox, record);
struct stat fileStat;
char path[MAX_MAILBOX_PATH+1] ;
// create user container if not there
snprintf(path, sizeof(path), "%s/%s", obj_def->namespace, obj_def->user);
if(stat(path, &fileStat) < 0) {
if (cyrus_mkdir (path, 755 ) == -1) {
syslog(LOG_ERR, "Dummy ObjectStore: Cannot create user %s",path);
rc = 1 ;
}
}
//create sub-container if not there
const char *container_path = objectstore_container_path(mailbox, record) ;
snprintf(path, sizeof(path), "%s/", container_path);
if(stat(path, &fileStat) < 0) {
if (cyrus_mkdir (path, 755 ) == -1) {
syslog(LOG_ERR, "Dummy ObjectStore: Cannot create user sub container %s",path);
rc = 1 ;
}
}
add_message_guid (mailbox, record) ;
// check is file already exist
rc = objectstore_is_filename_in_container (mailbox, record, &already);
if (!already) {
// copy file
const char *destfilename = objectstore_filename_in_container_path (mailbox, record) ;
rc = cyrus_copyfile (fname, destfilename, COPYFILE_NOLINK) ;
}
return rc;
}
int objectstore_get (struct mailbox *mailbox,
const struct index_record *record, const char *fname)
{
int already, rc = 0;
// check is file already exist
rc = objectstore_is_filename_in_container (mailbox, record, &already);
if (already) {
// copy file
const char *srcfilename = objectstore_filename_in_container_path (mailbox, record) ;
rc = cyrus_copyfile (srcfilename, fname, COPYFILE_NOLINK) ;
}
return rc;
}
int objectstore_delete (struct mailbox *mailbox,
const struct index_record *record)
{
static char path[MAX_MAILBOX_PATH+1];
int already, rc = 0;
// check is file already exist
rc = objectstore_is_filename_in_container (mailbox, record, &already);
if (already) {
int count = 0;
delete_message_guid (mailbox, record, &count) ;
if (!count){
// delete file
const char *filename = objectstore_filename_in_container_path (mailbox, record) ;
rc = remove ( filename ) ;
// remove empty sub-container
const char *container_path = objectstore_container_path(mailbox, record) ;
snprintf(path, sizeof(path), "%s/", container_path);
if(is_directory_empty (path))
remove (path) ;
}
}
return rc;
}
int objectstore_is_filename_in_container (struct mailbox *mailbox,
const struct index_record *record, int *isthere)
{
const char *filename = objectstore_filename_in_container_path (mailbox, record) ;
int rc = 0;
struct stat fileStat;
if(stat(filename, &fileStat) ==-1) {
rc = -1;
}
else *isthere = 1 ;
return rc;
}