00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011 #ifdef HAVE_CONFIG_H
00012 #include "config.h"
00013 #endif
00014
00015 #include <stdio.h>
00016 #include <stdlib.h>
00017 #include <string.h>
00018 #include <errno.h>
00019 #include <fcntl.h>
00020 #include <time.h>
00021 #include <libgen.h>
00022 #include <fuse/fuse.h>
00023 #ifdef HAVE_MYSQL_MYSQL_H
00024 #include <mysql/mysql.h>
00025 #endif
00026 #ifdef HAVE_MYSQL_H
00027 #include <mysql.h>
00028 #endif
00029
00030 #include "mysqlfs.h"
00031 #include "query.h"
00032 #include "log.h"
00033
00034 #define SQL_MAX 10240
00035 #define INODE_CACHE_MAX 4096
00036
00037 static inline int lock_inode(MYSQL *mysql, long inode)
00038 {
00039
00040 return 0;
00041 }
00042
00043 static inline int unlock_inode(MYSQL *mysql, long inode)
00044 {
00045
00046 return 0;
00047 }
00048
00049 static struct data_blocks_info *
00050 fill_data_blocks_info(struct data_blocks_info *info, size_t size, off_t offset)
00051 {
00052 info->seq_first = offset / DATA_BLOCK_SIZE;
00053 info->offset_first = offset % DATA_BLOCK_SIZE;
00054
00055 unsigned long nr_following_blocks = ((info->offset_first + size) / DATA_BLOCK_SIZE);
00056 info->length_first = nr_following_blocks > 0 ? DATA_BLOCK_SIZE - info->offset_first : size;
00057
00058 info->seq_last = info->seq_first + nr_following_blocks;
00059 info->length_last = (info->offset_first + size) % DATA_BLOCK_SIZE;
00060
00061
00062
00063 return info;
00064 }
00065
00079 int query_getattr(MYSQL *mysql, const char *path, struct stat *stbuf)
00080 {
00081 int ret;
00082 long inode, nlinks;
00083 char sql[SQL_MAX];
00084 MYSQL_RES* result;
00085 MYSQL_ROW row;
00086 ret = query_inode_full(mysql, path, NULL, 0, &inode, NULL, &nlinks);
00087 if (ret < 0)
00088 return ret;
00089
00090 snprintf(sql, SQL_MAX,
00091 "SELECT inode, mode, uid, gid, atime, mtime "
00092 "FROM inodes WHERE inode=%ld",
00093 inode);
00094
00095 log_printf(LOG_D_SQL, "sql=%s\n", sql);
00096
00097 ret = mysql_query(mysql, sql);
00098 if(ret){
00099 log_printf(LOG_ERROR, "ERROR: mysql_query()\n");
00100 log_printf(LOG_ERROR, "mysql_error: %s\n", mysql_error(mysql));
00101 return -EIO;
00102 }
00103
00104 result = mysql_store_result(mysql);
00105 if(!result){
00106 log_printf(LOG_ERROR, "ERROR: mysql_store_result()\n");
00107 log_printf(LOG_ERROR, "mysql_error: %s\n", mysql_error(mysql));
00108 return -EIO;
00109 }
00110
00111 if(mysql_num_rows(result) != 1){
00112 mysql_free_result(result);
00113 return -ENOENT;
00114 }
00115 row = mysql_fetch_row(result);
00116 if(!row){
00117 return -EIO;
00118 }
00119
00120 stbuf->st_ino = inode;
00121 stbuf->st_mode = atoi(row[1]);
00122 stbuf->st_uid = atol(row[2]);
00123 stbuf->st_gid = atol(row[3]);
00124 stbuf->st_atime = atol(row[4]);
00125 stbuf->st_mtime = atol(row[5]);
00126 stbuf->st_nlink = nlinks;
00127
00128 mysql_free_result(result);
00129
00130 return 0;
00131 }
00132
00154 int query_inode_full(MYSQL *mysql, const char *path, char *name, size_t name_len,
00155 long *inode, long *parent, long *nlinks)
00156 {
00157 long ret;
00158 char sql[SQL_MAX];
00159 MYSQL_RES* result;
00160 MYSQL_ROW row;
00161
00162 int depth = 0;
00163 char *pathptr = strdup(path), *pathptr_saved = pathptr;
00164 char *nameptr, *saveptr = NULL;
00165 char sql_from[SQL_MAX], sql_where[SQL_MAX];
00166 char *sql_from_end = sql_from, *sql_where_end = sql_where;
00167 char esc_name[PATH_MAX * 2];
00168
00169
00170 sql_from_end += snprintf(sql_from_end, SQL_MAX, "tree AS t0");
00171 sql_where_end += snprintf(sql_where_end, SQL_MAX, "t0.parent IS NULL");
00172 while ((nameptr = strtok_r(pathptr, "/", &saveptr)) != NULL) {
00173 if (depth++ == 0) {
00174 pathptr = NULL;
00175 }
00176
00177 mysql_real_escape_string(mysql, esc_name, nameptr, strlen(nameptr));
00178 sql_from_end += snprintf(sql_from_end, SQL_MAX, " LEFT JOIN tree AS t%d ON t%d.inode = t%d.parent",
00179 depth, depth-1, depth);
00180 sql_where_end += snprintf(sql_where_end, SQL_MAX, " AND t%d.name = '%s'",
00181 depth, esc_name);
00182 }
00183 free(pathptr_saved);
00184
00185
00186 snprintf(sql, SQL_MAX, "SELECT t%d.inode, t%d.name, t%d.parent, "
00187 " (SELECT COUNT(inode) FROM tree AS t%d WHERE t%d.inode=t%d.inode) "
00188 " AS nlinks "
00189 "FROM %s WHERE %s",
00190 depth, depth, depth,
00191 depth+1, depth+1, depth,
00192 sql_from, sql_where);
00193 log_printf(LOG_D_SQL, "sql=%s\n", sql);
00194 ret = mysql_query(mysql, sql);
00195 if(ret){
00196 log_printf(LOG_ERROR, "ERROR: mysql_query()\n");
00197 log_printf(LOG_ERROR, "mysql_error: %s\n", mysql_error(mysql));
00198 return -EIO;
00199 }
00200
00201 result = mysql_store_result(mysql);
00202 if(!result){
00203 log_printf(LOG_ERROR, "ERROR: mysql_store_result()\n");
00204 log_printf(LOG_ERROR, "mysql_error: %s\n", mysql_error(mysql));
00205 return -EIO;
00206 }
00207
00208 if(mysql_num_rows(result) != 1){
00209 mysql_free_result(result);
00210 return -ENOENT;
00211 }
00212
00213 row = mysql_fetch_row(result);
00214 if(!row){
00215 log_printf(LOG_ERROR, "ERROR: mysql_fetch_row()\n");
00216 return -EIO;
00217 }
00218 log_printf(LOG_D_OTHER, "query_inode(path='%s') => %s, %s, %s, %s\n",
00219 path, row[0], row[1], row[2], row[3]);
00220
00221 if (inode)
00222 *inode = atol(row[0]);
00223 if (name)
00224 snprintf(name, name_len, "%s", row[1]);
00225 if (parent)
00226 *parent = row[2] ? atol(row[2]) : -1;
00227 if (nlinks)
00228 *nlinks = atol(row[3]);
00229
00230 mysql_free_result(result);
00231
00232 return 0;
00233 }
00234
00245 long query_inode(MYSQL *mysql, const char *path)
00246 {
00247 long inode, ret;
00248
00249 ret = query_inode_full(mysql, path, NULL, 0, &inode, NULL, NULL);
00250 if (ret < 0)
00251 return ret;
00252 return inode;
00253 }
00254
00269 int query_truncate(MYSQL *mysql, const char *path, off_t length)
00270 {
00271 int ret;
00272 char sql[SQL_MAX];
00273 struct data_blocks_info info;
00274
00275 fill_data_blocks_info(&info, length, 0);
00276
00277 long inode = query_inode(mysql, path);
00278 if (inode < 0)
00279 return inode;
00280
00281 lock_inode(mysql, inode);
00282
00283 snprintf(sql, SQL_MAX,
00284 "DELETE FROM data_blocks WHERE inode=%ld AND seq > %ld",
00285 inode, info.seq_last);
00286 log_printf(LOG_D_SQL, "sql=%s\n", sql);
00287 if ((ret = mysql_query(mysql, sql))) goto err_out;
00288
00289 snprintf(sql, SQL_MAX,
00290 "UPDATE data_blocks SET data=RPAD(data, %zu, '\\0') "
00291 "WHERE inode=%ld AND seq=%ld",
00292 info.length_last, inode, info.seq_last);
00293 log_printf(LOG_D_SQL, "sql=%s\n", sql);
00294 if ((ret = mysql_query(mysql, sql))) goto err_out;
00295
00296 snprintf(sql, SQL_MAX,
00297 "UPDATE inodes SET size=%lld WHERE inode=%ld",
00298 length, inode);
00299 log_printf(LOG_D_SQL, "sql=%s\n", sql);
00300 if ((ret = mysql_query(mysql, sql))) goto err_out;
00301
00302 unlock_inode(mysql, inode);
00303
00304 return 0;
00305
00306 err_out:
00307 unlock_inode(mysql, inode);
00308 log_printf(LOG_ERROR, "mysql_error: %s\n", mysql_error(mysql));
00309 return ret;
00310 }
00311
00323 int query_mkdirentry(MYSQL *mysql, long inode, const char *name, long parent)
00324 {
00325 int ret;
00326 char sql[SQL_MAX];
00327 char esc_name[PATH_MAX * 2];
00328
00329 mysql_real_escape_string(mysql, esc_name, name, strlen(name));
00330 snprintf(sql, SQL_MAX,
00331 "INSERT INTO tree (name, parent, inode) VALUES ('%s', %ld, %ld)",
00332 esc_name, parent, inode);
00333
00334 log_printf(LOG_D_SQL, "sql=%s\n", sql);
00335 ret = mysql_query(mysql, sql);
00336 if(ret) {
00337 log_printf(LOG_ERROR, "mysql_error: %s\n", mysql_error(mysql));
00338 return -EIO;
00339 }
00340
00341 return 0;
00342 }
00343
00353 int query_rmdirentry(MYSQL *mysql, const char *name, long parent)
00354 {
00355 int ret;
00356 char sql[SQL_MAX];
00357 char esc_name[PATH_MAX * 2];
00358
00359 mysql_real_escape_string(mysql, esc_name, name, strlen(name));
00360 snprintf(sql, SQL_MAX,
00361 "DELETE FROM tree WHERE name='%s' AND parent=%ld",
00362 esc_name, parent);
00363
00364 log_printf(LOG_D_SQL, "sql=%s\n", sql);
00365 ret = mysql_query(mysql, sql);
00366 if(ret) {
00367 log_printf(LOG_ERROR, "mysql_error: %s\n", mysql_error(mysql));
00368 return -EIO;
00369 }
00370
00371 return 0;
00372 }
00373
00392 long query_mknod(MYSQL *mysql, const char *path, mode_t mode, dev_t rdev,
00393 long parent, int alloc_data)
00394 {
00395 int ret;
00396 char sql[SQL_MAX];
00397 long new_inode_number = 0;
00398 char *name, esc_name[PATH_MAX * 2];
00399
00400 if (path[0] == '/' && path[1] == '\0') {
00401 snprintf(sql, SQL_MAX,
00402 "INSERT INTO tree (name, parent) VALUES ('/', NULL)");
00403
00404 log_printf(LOG_D_SQL, "sql=%s\n", sql);
00405 ret = mysql_query(mysql, sql);
00406 if(ret)
00407 goto err_out;
00408 } else {
00409 name = strrchr(path, '/');
00410 if (!name || *++name == '\0')
00411 return -ENOENT;
00412
00413 mysql_real_escape_string(mysql, esc_name, name, strlen(name));
00414 snprintf(sql, SQL_MAX,
00415 "INSERT INTO tree (name, parent) VALUES ('%s', %ld)",
00416 esc_name, parent);
00417
00418 log_printf(LOG_D_SQL, "sql=%s\n", sql);
00419 ret = mysql_query(mysql, sql);
00420 if(ret)
00421 goto err_out;
00422 }
00423
00424 new_inode_number = mysql_insert_id(mysql);
00425
00426 snprintf(sql, SQL_MAX,
00427 "INSERT INTO inodes(inode, mode, uid, gid, atime, ctime, mtime)"
00428 "VALUES(%ld, %d, %d, %d, UNIX_TIMESTAMP(NOW()), "
00429 "UNIX_TIMESTAMP(NOW()), UNIX_TIMESTAMP(NOW()))",
00430 new_inode_number, mode,
00431 fuse_get_context()->uid, fuse_get_context()->gid);
00432
00433 log_printf(LOG_D_SQL, "sql=%s\n", sql);
00434 ret = mysql_query(mysql, sql);
00435 if(ret)
00436 goto err_out;
00437
00438 return new_inode_number;
00439
00440 err_out:
00441 log_printf(LOG_ERROR, "mysql_error: %s\n", mysql_error(mysql));
00442 return ret;
00443 }
00444
00456 long query_mkdir(MYSQL *mysql, const char *path, mode_t mode, long parent)
00457 {
00458 return query_mknod(mysql, path, S_IFDIR | mode, 0, parent, 0);
00459 }
00460
00478 int query_readdir(MYSQL *mysql, long inode, void *buf, fuse_fill_dir_t filler)
00479 {
00480 int ret;
00481 char sql[SQL_MAX];
00482 MYSQL_RES* result;
00483 MYSQL_ROW row;
00484
00485 snprintf(sql, sizeof(sql), "SELECT name FROM tree WHERE parent = '%ld'",
00486 inode);
00487
00488 ret = mysql_query(mysql, sql);
00489 if(ret){
00490 log_printf(LOG_ERROR, "mysql_error: %s\n", mysql_error(mysql));
00491 return -EIO;
00492 }
00493
00494 result = mysql_store_result(mysql);
00495 if(!result){
00496 log_printf(LOG_ERROR, "mysql_error: %s\n", mysql_error(mysql));
00497 return -EIO;
00498 }
00499
00500 while((row = mysql_fetch_row(result)) != NULL){
00501 filler(buf, (char*)basename(row[0]), NULL, 0);
00502 }
00503
00504 mysql_free_result(result);
00505
00506 return ret;
00507 }
00508
00521 int query_chmod(MYSQL *mysql, long inode, mode_t mode)
00522 {
00523 int ret;
00524 char sql[SQL_MAX];
00525
00526 snprintf(sql, SQL_MAX,
00527 "UPDATE inodes SET mode=%d WHERE inode=%ld",
00528 mode, inode);
00529
00530 log_printf(LOG_D_SQL, "sql=%s\n", sql);
00531
00532 ret = mysql_query(mysql, sql);
00533 if(ret){
00534 log_printf(LOG_ERROR, "Error: mysql_query()\n");
00535 log_printf(LOG_ERROR, "mysql_error: %s\n", mysql_error(mysql));
00536 return -EIO;
00537 }
00538
00539 return 0;
00540 }
00541
00555 int query_chown(MYSQL *mysql, long inode, uid_t uid, gid_t gid)
00556 {
00557 int ret;
00558 char sql[SQL_MAX];
00559 size_t index;
00560
00561 index = snprintf(sql, SQL_MAX, "UPDATE inodes SET ");
00562 if (uid != (uid_t)-1)
00563 index += snprintf(sql + index, SQL_MAX - index,
00564 "uid=%d ", uid);
00565 if (gid != (gid_t)-1)
00566 index += snprintf(sql + index, SQL_MAX - index,
00567 "%s gid=%d ",
00568
00569 (uid != (uid_t)-1) ? "," : "",
00570 gid);
00571 snprintf(sql + index, SQL_MAX - index, "WHERE inode=%ld", inode);
00572
00573 log_printf(LOG_D_SQL, "sql=%s\n", sql);
00574
00575 ret = mysql_query(mysql, sql);
00576 if(ret){
00577 log_printf(LOG_ERROR, "mysql_error: %s\n", mysql_error(mysql));
00578 return -EIO;
00579 }
00580
00581 return 0;
00582 }
00583
00597 int query_utime(MYSQL *mysql, long inode, struct utimbuf *time)
00598 {
00599 int ret;
00600 char sql[SQL_MAX];
00601
00602 snprintf(sql, SQL_MAX,
00603 "UPDATE inodes "
00604 "SET atime=%ld, mtime=%ld "
00605 "WHERE inode=%lu",
00606 time->actime, time->modtime, inode);
00607
00608 log_printf(LOG_D_SQL, "sql=%s\n", sql);
00609
00610 ret = mysql_query(mysql, sql);
00611 if(ret){
00612 log_printf(LOG_ERROR, "Error: mysql_query()\n");
00613 log_printf(LOG_ERROR, "mysql_error: %s\n", mysql_error(mysql));
00614 return -EIO;
00615 }
00616
00617 return 0;
00618 }
00619
00634 int query_read(MYSQL *mysql, long inode, const char *buf, size_t size,
00635 off_t offset)
00636 {
00637 int ret;
00638 char sql[SQL_MAX];
00639 MYSQL_RES* result;
00640 MYSQL_ROW row;
00641 unsigned long length = 0L, copy_len, seq;
00642 struct data_blocks_info info;
00643 char *dst = (char *)buf;
00644 char *src, *zeroes = alloca(DATA_BLOCK_SIZE);
00645
00646 fill_data_blocks_info(&info, size, offset);
00647
00648
00649 snprintf(sql, SQL_MAX,
00650 "SELECT seq, data, LENGTH(data) FROM data_blocks WHERE inode=%ld AND seq>=%lu AND seq <=%lu ORDER BY seq ASC",
00651 inode, info.seq_first, info.seq_last);
00652
00653 log_printf(LOG_D_SQL, "sql=%s\n", sql);
00654
00655 ret = mysql_query(mysql, sql);
00656 if(ret){
00657 log_printf(LOG_ERROR, "ERROR: mysql_query()\n");
00658 log_printf(LOG_ERROR, "mysql_error: %s\n", mysql_error(mysql));
00659 return -EIO;
00660 }
00661
00662 result = mysql_store_result(mysql);
00663 if(!result){
00664 log_printf(LOG_ERROR, "ERROR: mysql_store_result()\n");
00665 log_printf(LOG_ERROR, "mysql_error: %s\n", mysql_error(mysql));
00666 return -EIO;
00667 }
00668
00669
00670
00671
00672
00673 row = mysql_fetch_row(result);
00674 memset(zeroes, 0L, DATA_BLOCK_SIZE);
00675 for (seq = info.seq_first; seq<=info.seq_last; seq++) {
00676 off_t row_seq = -1;
00677 size_t row_len = DATA_BLOCK_SIZE;
00678 char *data = zeroes;
00679
00680 if (row && (row_seq = atoll(row[0])) == seq) {
00681 data = row[1];
00682 row_len = atoll(row[2]);
00683 }
00684
00685 if (seq == info.seq_first) {
00686 if (row_len < info.offset_first)
00687 goto go_away;
00688
00689 copy_len = MIN(row_len - info.offset_first, info.length_first);
00690 src = data + info.offset_first;
00691 } else if (seq == info.seq_last) {
00692 copy_len = MIN(info.length_last, row_len);
00693 src = data;
00694 } else {
00695 copy_len = MIN(DATA_BLOCK_SIZE, row_len);
00696 src = data;
00697 }
00698
00699 memcpy(dst, src, copy_len);
00700 dst += copy_len;
00701 length += copy_len;
00702
00703 if (row && row_seq == seq)
00704 row = mysql_fetch_row(result);
00705 }
00706
00707 go_away:
00708
00709 while (mysql_fetch_row(result));
00710 mysql_free_result(result);
00711
00712 return length;
00713 }
00714
00736 static int write_one_block(MYSQL *mysql, long inode,
00737 unsigned long seq,
00738 const char *data, size_t size,
00739 off_t offset)
00740 {
00741 MYSQL_STMT *stmt;
00742 MYSQL_BIND bind[1];
00743 char sql[SQL_MAX];
00744 size_t current_block_size = query_size_block(mysql, inode, seq);
00745
00746
00747 if (size == 0) return 0;
00748
00749 if (offset + size > DATA_BLOCK_SIZE) {
00750 log_printf(LOG_ERROR, "%s(): offset(%zu)+size(%zu)>max_block(%d)\n",
00751 __func__, offset, size, DATA_BLOCK_SIZE);
00752 return -EIO;
00753 }
00754
00755
00756
00757 if (current_block_size == -ENXIO) {
00758
00759 snprintf(sql, SQL_MAX,
00760 "INSERT INTO data_blocks SET inode=%ld, seq=%lu, data=''", inode, seq);
00761 log_printf(LOG_D_SQL, "sql=%s\n", sql);
00762 if(mysql_query(mysql, sql)){
00763 log_printf(LOG_ERROR, "mysql_error: %s\n", mysql_error(mysql));
00764 return -EIO;
00765 }
00766
00767 current_block_size = query_size_block(mysql, inode, seq);
00768 }
00769
00770 stmt = mysql_stmt_init(mysql);
00771 if (!stmt)
00772 {
00773 log_printf(LOG_ERROR, "mysql_stmt_init(), out of memory\n");
00774 return -EIO;
00775 }
00776
00777 memset(bind, 0, sizeof(bind));
00778 if (offset == 0 && current_block_size == 0) {
00779 snprintf(sql, SQL_MAX,
00780 "UPDATE data_blocks "
00781 "SET data=? "
00782 "WHERE inode=%ld AND seq=%lu",
00783 inode, seq);
00784 } else if (offset == current_block_size) {
00785 snprintf(sql, sizeof(sql),
00786 "UPDATE data_blocks "
00787 "SET data=CONCAT(data, ?) "
00788 "WHERE inode=%ld AND seq=%lu",
00789 inode, seq);
00790 } else {
00791 size_t pos, new_size;
00792 pos = snprintf(sql, sizeof(sql),
00793 "UPDATE data_blocks SET data=CONCAT(");
00794 if (offset > 0)
00795 pos += snprintf(sql + pos, sizeof(sql) - pos, "RPAD(IF(ISNULL(data),'', data), %llu, '\\0'),", offset);
00796 pos += snprintf(sql + pos, sizeof(sql) - pos, "?,");
00797 new_size = offset + size;
00798 if (offset + size < current_block_size) {
00799 pos += snprintf(sql + pos, sizeof(sql) - pos, "SUBSTRING(data FROM %llu),", offset + size + 1);
00800 new_size = current_block_size;
00801 }
00802 sql[--pos] = '\0';
00803 pos += snprintf(sql + pos, sizeof(sql) - pos, ") WHERE inode=%ld AND seq=%lu",
00804 inode, seq);
00805 }
00806 log_printf(LOG_D_SQL, "sql=%s\n", sql);
00807
00808 if (mysql_stmt_prepare(stmt, sql, strlen(sql))) {
00809 log_printf(LOG_ERROR, "mysql_stmt_prepare() failed: %s\n", mysql_stmt_error(stmt));
00810 goto err_out;
00811 }
00812
00813 if (mysql_stmt_param_count(stmt) != 1) {
00814 log_printf(LOG_ERROR, "%s(): stmt_param_count=%d, expected 1\n", __func__, mysql_stmt_param_count(stmt));
00815 return -EIO;
00816 }
00817 bind[0].buffer_type= MYSQL_TYPE_LONG_BLOB;
00818 bind[0].buffer= (char *)data;
00819 bind[0].is_null= 0;
00820 bind[0].length= (unsigned long *)(void *)&size;
00821
00822 if (mysql_stmt_bind_param(stmt, bind)) {
00823 log_printf(LOG_ERROR, "mysql_stmt_bind_param() failed: %s\n", mysql_stmt_error(stmt));
00824 goto err_out;
00825 }
00826
00827
00828
00829
00830
00831
00832
00833
00834 if (mysql_stmt_execute(stmt)) {
00835 log_printf(LOG_ERROR, "mysql_stmt_execute() failed: %s\n", mysql_stmt_error(stmt));
00836 goto err_out;
00837 }
00838
00839 if (mysql_stmt_close(stmt))
00840 log_printf(LOG_ERROR, "failed closing the statement: %s\n", mysql_stmt_error(stmt));
00841
00842
00843 snprintf(sql, SQL_MAX,
00844 "UPDATE inodes SET size=("
00845 "SELECT seq*%d + LENGTH(data) FROM data_blocks WHERE inode=%ld AND seq=("
00846 "SELECT MAX(seq) FROM data_blocks WHERE inode=%ld"
00847 ")"
00848 ") "
00849 "WHERE inode=%ld",
00850 DATA_BLOCK_SIZE, inode, inode, inode);
00851 log_printf(LOG_D_SQL, "sql=%s\n", sql);
00852 if(mysql_query(mysql, sql)) {
00853 log_printf(LOG_ERROR, "mysql_error: %s\n", mysql_error(mysql));
00854 return -EIO;
00855 }
00856
00857 return size;
00858
00859 err_out:
00860 log_printf(LOG_ERROR, " %s\n", mysql_stmt_error(stmt));
00861 if (mysql_stmt_close(stmt))
00862 log_printf(LOG_ERROR, "failed closing the statement: %s\n", mysql_stmt_error(stmt));
00863 return -EIO;
00864 }
00865
00879 int query_write(MYSQL *mysql, long inode, const char *data, size_t size,
00880 off_t offset)
00881 {
00882 struct data_blocks_info info;
00883 unsigned long seq;
00884 const char *ptr;
00885 int ret, ret_size = 0;
00886
00887 fill_data_blocks_info(&info, size, offset);
00888
00889
00890 lock_inode(mysql, inode);
00891 ret = write_one_block(mysql, inode, info.seq_first, data,
00892 info.length_first, info.offset_first);
00893 unlock_inode(mysql, inode);
00894 if (ret < 0)
00895 return ret;
00896 ret_size = ret;
00897
00898
00899
00900 if (info.seq_first == info.seq_last)
00901 return ret_size;
00902
00903 ptr = data + info.length_first;
00904
00905
00906 for (seq = info.seq_first + 1; seq < info.seq_last; seq++) {
00907 lock_inode(mysql, inode);
00908 ret = write_one_block(mysql, inode, seq, ptr, DATA_BLOCK_SIZE, 0);
00909 unlock_inode(mysql, inode);
00910 if (ret < 0)
00911 return ret;
00912 ptr += DATA_BLOCK_SIZE;
00913 ret_size += ret;
00914 }
00915
00916
00917 lock_inode(mysql, inode);
00918 ret = write_one_block(mysql, inode, info.seq_last, ptr,
00919 info.length_last, 0);
00920 unlock_inode(mysql, inode);
00921 if (ret < 0)
00922 return ret;
00923 ret_size += ret;
00924
00925 return ret_size;
00926 }
00927
00940 ssize_t query_size(MYSQL *mysql, long inode)
00941 {
00942 size_t ret;
00943 char sql[SQL_MAX];
00944 MYSQL_RES *result;
00945 MYSQL_ROW row;
00946
00947 snprintf(sql, SQL_MAX, "SELECT size FROM inodes WHERE inode=%ld",
00948 inode);
00949
00950 ret = mysql_query(mysql, sql);
00951 if(ret){
00952 log_printf(LOG_ERROR, "mysql_error: %s\n", mysql_error(mysql));
00953 return -EIO;
00954 }
00955 log_printf(LOG_D_SQL, "sql=%s\n", sql);
00956
00957 result = mysql_store_result(mysql);
00958 if(!result){
00959 log_printf(LOG_ERROR, "ERROR: mysql_store_result()\n");
00960 log_printf(LOG_ERROR, "mysql_error: %s\n", mysql_error(mysql));
00961 return -EIO;
00962 }
00963
00964 if(mysql_num_rows(result) != 1 || mysql_num_fields(result) != 1){
00965 mysql_free_result(result);
00966 return -EIO;
00967 }
00968
00969 row = mysql_fetch_row(result);
00970 if(!row){
00971 return -EIO;
00972 }
00973
00974 if(row[0]){
00975 ret = atoll(row[0]);
00976 }else{
00977 ret = 0;
00978 }
00979 mysql_free_result(result);
00980
00981 return ret;
00982 }
00983
00995 ssize_t query_size_block(MYSQL *mysql, long inode, unsigned long seq)
00996 {
00997 size_t ret;
00998 char sql[SQL_MAX];
00999 MYSQL_RES *result;
01000 MYSQL_ROW row;
01001
01002 snprintf(sql, SQL_MAX, "SELECT LENGTH(data) FROM data_blocks WHERE inode=%ld AND seq=%lu",
01003 inode, seq);
01004
01005 ret = mysql_query(mysql, sql);
01006 if(ret){
01007 log_printf(LOG_ERROR, "mysql_error: %s\n", mysql_error(mysql));
01008 return -EIO;
01009 }
01010 log_printf(LOG_D_SQL, "sql=%s\n", sql);
01011
01012 result = mysql_store_result(mysql);
01013 if(!result){
01014 log_printf(LOG_ERROR, "ERROR: mysql_store_result()\n");
01015 log_printf(LOG_ERROR, "mysql_error: %s\n", mysql_error(mysql));
01016 return -EIO;
01017 }
01018
01019 if(mysql_num_rows(result) == 0) {
01020 mysql_free_result(result);
01021 return -ENXIO;
01022 }
01023
01024 row = mysql_fetch_row(result);
01025 if(!row){
01026 return -EIO;
01027 }
01028
01029 if(row[0]){
01030 ret = atoll(row[0]);
01031 }else{
01032 ret = 0;
01033 }
01034 mysql_free_result(result);
01035
01036 return ret;
01037 }
01038
01050 int query_rename(MYSQL *mysql, const char *from, const char *to)
01051 {
01052 int ret;
01053 long inode, parent_to, parent_from;
01054 char *tmp, *new_name, *old_name;
01055 char esc_new_name[PATH_MAX * 2], esc_old_name[PATH_MAX * 2];
01056 char sql[SQL_MAX];
01057
01058 inode = query_inode(mysql, from);
01059
01060
01061
01062 tmp = strdup(from);
01063 parent_from = query_inode(mysql, dirname(tmp));
01064 free(tmp);
01065
01066 tmp = strdup(from);
01067 old_name = basename(tmp);
01068 mysql_real_escape_string(mysql, esc_old_name, old_name, strlen(old_name));
01069 free(tmp);
01070
01071 tmp = strdup(to);
01072 parent_to = query_inode(mysql, dirname(tmp));
01073 free(tmp);
01074
01075 tmp = strdup(to);
01076 new_name = basename(tmp);
01077 mysql_real_escape_string(mysql, esc_new_name, new_name, strlen(new_name));
01078 free(tmp);
01079
01080 snprintf(sql, SQL_MAX,
01081 "UPDATE tree "
01082 "SET name='%s', parent=%ld "
01083 "WHERE inode=%ld AND name='%s' AND parent=%ld ",
01084 esc_new_name, parent_to,
01085 inode, esc_old_name, parent_from);
01086
01087 log_printf(LOG_D_SQL, "sql=%s\n", sql);
01088
01089 ret = mysql_query(mysql, sql);
01090 if(ret){
01091 log_printf(LOG_ERROR, "Error: mysql_query()\n");
01092 log_printf(LOG_ERROR, "mysql_error: %s\n", mysql_error(mysql));
01093 return -EIO;
01094 }
01095
01096
01097
01098
01099
01100
01101 return 0;
01102 }
01103
01114 int query_inuse_inc(MYSQL *mysql, long inode, int increment)
01115 {
01116 int ret;
01117 char sql[SQL_MAX];
01118
01119 snprintf(sql, SQL_MAX,
01120 "UPDATE inodes SET inuse = inuse + %d "
01121 "WHERE inode=%lu",
01122 increment, inode);
01123
01124 log_printf(LOG_D_SQL, "sql=%s\n", sql);
01125
01126 ret = mysql_query(mysql, sql);
01127 if(ret){
01128 log_printf(LOG_ERROR, "Error: mysql_query()\n");
01129 log_printf(LOG_ERROR, "mysql_error: %s\n", mysql_error(mysql));
01130 return -EIO;
01131 }
01132
01133 return 0;
01134 }
01135
01144 int query_purge_deleted(MYSQL *mysql, long inode)
01145 {
01146 int ret;
01147 char sql[SQL_MAX];
01148
01149 snprintf(sql, SQL_MAX,
01150 "DELETE FROM inodes WHERE inode=%ld AND inuse=0 AND deleted=1",
01151 inode);
01152
01153 log_printf(LOG_D_SQL, "sql=%s\n", sql);
01154
01155 ret = mysql_query(mysql, sql);
01156 if(ret){
01157 log_printf(LOG_ERROR, "Error: mysql_query()\n");
01158 log_printf(LOG_ERROR, "mysql_error: %s\n", mysql_error(mysql));
01159 return -EIO;
01160 }
01161
01162 return 0;
01163 }
01164
01174 int query_set_deleted(MYSQL *mysql, long inode)
01175 {
01176 int ret;
01177 char sql[SQL_MAX];
01178
01179 snprintf(sql, SQL_MAX,
01180 "UPDATE inodes LEFT JOIN tree ON inodes.inode = tree.inode SET inodes.deleted=1 "
01181 "WHERE inodes.inode = %ld AND tree.name IS NULL",
01182 inode);
01183
01184 log_printf(LOG_D_SQL, "sql=%s\n", sql);
01185
01186 ret = mysql_query(mysql, sql);
01187 if(ret){
01188 log_printf(LOG_ERROR, "Error: mysql_query()\n");
01189 log_printf(LOG_ERROR, "mysql_error: %s\n", mysql_error(mysql));
01190 return -EIO;
01191 }
01192
01193 return 0;
01194 }
01195
01209 int query_fsck(MYSQL *mysql)
01210 {
01211
01212
01213
01214
01215 printf("Starting fsck\n");
01216
01217
01218 int ret;
01219
01220 int result;
01221 char sql[SQL_MAX];
01222 printf("Stage 1...\n");
01223 snprintf(sql, SQL_MAX,
01224 "DELETE from inodes WHERE inodes.deleted = 1");
01225
01226 log_printf(LOG_D_SQL, "sql=%s\n", sql);
01227
01228 ret = mysql_query(mysql, sql);
01229 if(ret){
01230 log_printf(LOG_ERROR, "Error: mysql_query()\n");
01231 log_printf(LOG_ERROR, "mysql_error: %s\n", mysql_error(mysql));
01232 return -EIO;
01233 }
01234
01235 printf("Stage 2...\n");
01236 snprintf(sql, SQL_MAX, "delete from tree where tree.inode not in (select inode from inodes);");
01237
01238 log_printf(LOG_D_SQL, "sql=%s\n", sql);
01239 ret = mysql_query(mysql, sql);
01240
01241 if(ret){
01242 log_printf(LOG_ERROR, "Error: mysql_query()\n");
01243 log_printf(LOG_ERROR, "mysql_error: %s\n", mysql_error(mysql));
01244 return -EIO;
01245 }
01246
01247
01248
01249
01250 printf("Stage 3...\n");
01251 snprintf(sql, SQL_MAX, "UPDATE inodes SET inuse=0;");
01252
01253 log_printf(LOG_D_SQL, "sql=%s\n", sql);
01254
01255 ret = mysql_query(mysql, sql);
01256 if(ret){
01257 log_printf(LOG_ERROR, "Error: mysql_query()\n");
01258 log_printf(LOG_ERROR, "mysql_error: %s\n", mysql_error(mysql));
01259 return -EIO;
01260 }
01261
01262
01263
01264 printf("Stage 4...\n");
01265 snprintf(sql, SQL_MAX, "delete from data_blocks where inode not in (select inode from inodes);");
01266
01267 log_printf(LOG_D_SQL, "sql=%s\n", sql);
01268
01269 ret = mysql_query(mysql, sql);
01270 if(ret){
01271 log_printf(LOG_ERROR, "Error: mysql_query()\n");
01272 log_printf(LOG_ERROR, "mysql_error: %s\n", mysql_error(mysql));
01273 return -EIO;
01274 }
01275
01276
01277
01278 printf("Stage 5...\n");
01279 long int inode;
01280 long int size;
01281
01282 snprintf(sql, SQL_MAX, "select inode, sum(OCTET_LENGTH(data)) as size from data_blocks group by inode");
01283
01284 log_printf(LOG_D_SQL, "sql=%s\n", sql);
01285
01286 ret = mysql_query(mysql, sql);
01287
01288 MYSQL_RES* myresult;
01289 MYSQL_ROW row;
01290
01291 myresult = mysql_store_result(mysql);
01292 while ((row = mysql_fetch_row(myresult)) != NULL) {
01293 inode = atol(row[0]);
01294 size = atol(row[1]);
01295
01296 snprintf(sql, SQL_MAX, "update inodes set size=%ld where inode=%ld;", size, inode);
01297 log_printf(LOG_D_SQL, "sql=%s\n", sql);
01298 result = mysql_query(mysql, sql);
01299
01300
01301
01302
01303
01304
01305
01306
01307
01308
01309 }
01310
01311 if(ret){
01312 log_printf(LOG_ERROR, "Error: mysql_query()\n");
01313 log_printf(LOG_ERROR, "mysql_error: %s\n", mysql_error(mysql));
01314 return -EIO;
01315 }
01316 mysql_free_result(myresult);
01317
01318
01319
01320
01321
01322
01323
01324
01325
01326
01327
01328
01329
01330
01331 printf("fsck done!\n");
01332 return ret;
01333
01334 }