/** * @brief Get the handle of a file, knowing its name and its parent dir * * @param p_context * @param p_parent_dir_handle * Handle of the parent directory * @param p_fsalname * Name of the object * @param p_infofs * Information about the file (taken from the filesystem) to be compared to information stored in database * @param p_object_handle * Handle of the file. * * @return * ERR_FSAL_NOERR, if no error * Anothere error code else. */ fsal_status_t fsal_internal_getInfoFromName(posixfsal_op_context_t * p_context, /* IN */ posixfsal_handle_t * p_parent_dir_handle, /* IN */ fsal_name_t * p_fsalname, /* IN */ fsal_posixdb_fileinfo_t * p_infofs, /* IN */ posixfsal_handle_t * p_object_handle) /* OUT */ { fsal_posixdb_status_t stdb; fsal_status_t st; stdb = fsal_posixdb_getInfoFromName(p_context->p_conn, p_parent_dir_handle, p_fsalname, NULL, p_object_handle); switch (stdb.major) { case ERR_FSAL_POSIXDB_NOERR: /* No error, the object is in the database */ /* check consistency */ if(fsal_posixdb_consistency_check(&(p_object_handle->data.info), p_infofs)) { /* Entry not consistent */ /* Delete the Handle entry, then add a new one (with a Parent entry) */ stdb = fsal_posixdb_deleteHandle(p_context->p_conn, p_object_handle); if(FSAL_POSIXDB_IS_ERROR(stdb) && FSAL_IS_ERROR(st = posixdb2fsal_error(stdb))) return st; /* don't break, add a new entry */ } else { break; } case ERR_FSAL_POSIXDB_NOENT: /* object not in the database, add a new entry */ st = fsal_internal_posixdb_add_entry(p_context->p_conn, p_fsalname, p_infofs, p_parent_dir_handle, p_object_handle); if(FSAL_IS_ERROR(st)) return st; break; default: /* error */ if(FSAL_IS_ERROR(st = posixdb2fsal_error(stdb))) return st; } ReturnCode(ERR_FSAL_NO_ERROR, 0); }
fsal_posixdb_status_t fsal_posixdb_internal_delete(fsal_posixdb_conn * p_conn, /* IN */ char *handleidparent_str, /* IN */ char *handletsparent_str, /* IN */ char *filename, /* IN */ fsal_posixdb_fileinfo_t * p_object_info /* IN */ ) { PGresult *p_res; char handleid_str[MAX_HANDLEIDSTR_SIZE]; char handlets_str[MAX_HANDLETSSTR_SIZE]; fsal_posixdb_status_t st; fsal_posixdb_fileinfo_t infodb; const char *paramValues[3]; if(!p_conn || !handleidparent_str || !handletsparent_str || !filename) ReturnCodeDB(ERR_FSAL_POSIXDB_FAULT, 0); paramValues[0] = handleidparent_str; paramValues[1] = handletsparent_str; paramValues[2] = filename; p_res = PQexecPrepared(p_conn, "lookupHandleByNameFU", 3, paramValues, NULL, NULL, 0); CheckResult(p_res); /* p_res contains : handleid, handlets, deviceId, inode, nlink, ctime, ftype */ /* no entry found */ if(PQntuples(p_res) != 1) { ReturnCodeDB(ERR_FSAL_POSIXDB_NOENT, 0); } strncpy(handleid_str, PQgetvalue(p_res, 0, 0), MAX_HANDLEIDSTR_SIZE); strncpy(handlets_str, PQgetvalue(p_res, 0, 1), MAX_HANDLETSSTR_SIZE); /* consistency check */ /* fill 'infodb' with information about the handle in the database */ posixdb_internal_fillFileinfoFromStrValues(&infodb, PQgetvalue(p_res, 0, 2), /* no need to compare inode & devid, they are the same */ PQgetvalue(p_res, 0, 3), PQgetvalue(p_res, 0, 4), /* nlink */ PQgetvalue(p_res, 0, 5), /* ctime */ PQgetvalue(p_res, 0, 6) /* ftype */ ); PQclear(p_res); if(p_object_info && fsal_posixdb_consistency_check(&infodb, p_object_info)) { /* not consistent, the bad handle have to be deleted */ LogCrit(COMPONENT_FSAL, "Consistency check failed while deleting a Path : Handle deleted"); infodb.ftype = FSAL_TYPE_DIR; /* considers that the entry is a directory in order to delete all its Parent entries and its Handle */ } switch (infodb.ftype) { case FSAL_TYPE_DIR: /* directory */ st = fsal_posixdb_recursiveDelete(p_conn, handleid_str, handlets_str, infodb.ftype); break; default: st = fsal_posixdb_deleteParent(p_conn, handleid_str, handlets_str, handleidparent_str, handletsparent_str, filename, infodb.nlink); } return st; }
fsal_posixdb_status_t fsal_posixdb_add(fsal_posixdb_conn * p_conn, /* IN */ fsal_posixdb_fileinfo_t * p_object_info, /* IN */ posixfsal_handle_t * p_parent_directory_handle, /* IN */ fsal_name_t * p_filename, /* IN */ posixfsal_handle_t * p_object_handle /* OUT */ ) { PGresult *p_res; char handleid_str[MAX_HANDLEIDSTR_SIZE]; char handlets_str[MAX_HANDLETSSTR_SIZE]; char handleidparent_str[MAX_HANDLEIDSTR_SIZE]; char handletsparent_str[MAX_HANDLETSSTR_SIZE]; char devid_str[MAX_DEVICEIDSTR_SIZE]; char inode_str[MAX_INODESTR_SIZE]; int found; const char *paramValues[6]; fsal_posixdb_status_t st; /******************* * 1/ sanity check * *******************/ /* parent_directory and filename are NULL only if it is the root directory */ if(!p_conn || !p_object_info || !p_object_handle || (p_filename && !p_parent_directory_handle) || (!p_filename && p_parent_directory_handle)) ReturnCodeDB(ERR_FSAL_POSIXDB_FAULT, 0); CheckConn(p_conn); LogFullDebug(COMPONENT_FSAL, "adding entry with parentid=%llu, id=%"PRIu64", name=%s\n", p_parent_directory_handle ? p_parent_directory_handle->data.id : 0, p_object_info ? p_object_info->inode : 0, p_filename ? p_filename->name : "NULL"); BeginTransaction(p_conn, p_res); /********************************* * 2/ we check the parent handle * *********************************/ if(p_parent_directory_handle) { /* the root has no parent */ snprintf(handleidparent_str, MAX_HANDLEIDSTR_SIZE, "%llu", p_parent_directory_handle->data.id); snprintf(handletsparent_str, MAX_HANDLETSSTR_SIZE, "%i", p_parent_directory_handle->data.ts); paramValues[0] = handleidparent_str; paramValues[1] = handletsparent_str; p_res = PQexecPrepared(p_conn, "lookupHandle", 2, paramValues, NULL, NULL, 0); CheckResult(p_res); if(PQntuples(p_res) != 1) { /* parent entry not found */ RollbackTransaction(p_conn, p_res); ReturnCodeDB(ERR_FSAL_POSIXDB_NOENT, 0); } PQclear(p_res); } /********************************************************** * 3/ Check if there is an existing Handle for the object * **********************************************************/ snprintf(devid_str, MAX_DEVICEIDSTR_SIZE, "%llu", (unsigned long long int)p_object_info->devid); snprintf(inode_str, MAX_INODESTR_SIZE, "%llu", (unsigned long long int)p_object_info->inode); paramValues[0] = devid_str; paramValues[1] = inode_str; p_res = PQexecPrepared(p_conn, "lookupHandleByInodeFU", 2, paramValues, NULL, NULL, 0); CheckResult(p_res); found = (PQntuples(p_res) == 1); if(found) { /* a Handle (that matches devid & inode) already exists */ /* fill 'info' with information about the handle in the database */ posixdb_internal_fillFileinfoFromStrValues(&(p_object_handle->data.info), NULL, NULL, PQgetvalue(p_res, 0, 2), /* nlink */ PQgetvalue(p_res, 0, 3), /* ctime */ PQgetvalue(p_res, 0, 4) /* ftype */ ); p_object_handle->data.info.inode = p_object_info->inode; p_object_handle->data.info.devid = p_object_info->devid; strncpy(handleid_str, PQgetvalue(p_res, 0, 0), MAX_HANDLEIDSTR_SIZE); strncpy(handlets_str, PQgetvalue(p_res, 0, 1), MAX_HANDLETSSTR_SIZE); PQclear(p_res); p_object_handle->data.id = atoll(handleid_str); p_object_handle->data.ts = atoi(handlets_str); /* check the consistency of the handle */ if(fsal_posixdb_consistency_check(&(p_object_handle->data.info), p_object_info)) { /* consistency check failed */ /* p_object_handle has been filled in order to be able to fix the consistency later */ RollbackTransaction(p_conn, p_res); ReturnCodeDB(ERR_FSAL_POSIXDB_CONSISTENCY, 0); } /* update nlink & ctime if needed */ if(p_object_info->nlink != p_object_handle->data.info.nlink || p_object_info->ctime != p_object_handle->data.info.ctime) { char nlink_str[MAX_NLINKSTR_SIZE]; char ctime_str[MAX_CTIMESTR_SIZE]; snprintf(nlink_str, MAX_NLINKSTR_SIZE, "%i", p_object_info->nlink); snprintf(ctime_str, MAX_CTIMESTR_SIZE, "%i", (int)p_object_info->ctime); paramValues[0] = handleid_str; paramValues[1] = handlets_str; paramValues[2] = nlink_str; paramValues[3] = ctime_str; p_object_handle->data.info = *p_object_info; p_res = PQexecPrepared(p_conn, "updateHandle", 4, paramValues, NULL, NULL, 0); CheckCommand(p_res); } fsal_posixdb_UpdateInodeCache(p_object_handle); } else { /* no handle found */ /* Handle does not exist, add a new Handle entry */ char nlink_str[MAX_NLINKSTR_SIZE]; char ctime_str[MAX_CTIMESTR_SIZE]; char ftype_str[MAX_FTYPESTR_SIZE]; PQclear(p_res); p_object_handle->data.ts = (int)time(NULL); p_object_handle->data.info = *p_object_info; snprintf(handlets_str, MAX_HANDLETSSTR_SIZE, "%i", p_object_handle->data.ts); snprintf(nlink_str, MAX_NLINKSTR_SIZE, "%i", p_object_info->nlink); snprintf(ctime_str, MAX_CTIMESTR_SIZE, "%i", (int)p_object_info->ctime); snprintf(ftype_str, MAX_CTIMESTR_SIZE, "%i", (int)p_object_info->ftype); paramValues[0] = devid_str; paramValues[1] = inode_str; paramValues[2] = handlets_str; paramValues[3] = nlink_str; paramValues[4] = ctime_str; paramValues[5] = ftype_str; p_res = PQexecPrepared(p_conn, "insertHandle", 6, paramValues, NULL, NULL, 0); CheckCommand(p_res); PQclear(p_res); p_res = PQexecPrepared(p_conn, "lookupHandleByInodeFU", 2, paramValues, NULL, NULL, 0); CheckResult(p_res); strncpy(handleid_str, PQgetvalue(p_res, 0, 0), MAX_HANDLEIDSTR_SIZE); strncpy(handlets_str, PQgetvalue(p_res, 0, 1), MAX_HANDLETSSTR_SIZE); p_object_handle->data.id = atoll(PQgetvalue(p_res, 0, 0)); PQclear(p_res); /* now, we have the handle id */ fsal_posixdb_UpdateInodeCache(p_object_handle); } /************************************************ * add (or update) an entry in the Parent table * ************************************************/ paramValues[0] = p_parent_directory_handle ? handleidparent_str : handleid_str; paramValues[1] = p_parent_directory_handle ? handletsparent_str : handlets_str; paramValues[2] = p_filename ? p_filename->name : ""; p_res = PQexecPrepared(p_conn, "lookupParent", 3, paramValues, NULL, NULL, 0); CheckResult(p_res); /* p-res contains handleid & handlets */ found = (PQntuples(p_res) == 1); paramValues[3] = handleid_str; paramValues[4] = handlets_str; if(found) { /* update the Parent entry if necessary (there entry exists with another handle) */ if((fsal_u64_t) atoll(PQgetvalue(p_res, 0, 0)) != p_object_handle->data.id || atoi(PQgetvalue(p_res, 0, 1)) != p_object_handle->data.ts) { /* steps : - check the nlink value of the Parent entry to be overwritten - if nlink = 1, then we can delete the handle. else we have to update it (nlink--) : that is done by fsal_posixdb_deleteParent - update the handle of the entry */ char bad_handleid_str[MAX_HANDLEIDSTR_SIZE]; char bad_handlets_str[MAX_HANDLETSSTR_SIZE]; int nlink; strncpy(bad_handleid_str, PQgetvalue(p_res, 0, 0), MAX_HANDLEIDSTR_SIZE); strncpy(bad_handlets_str, PQgetvalue(p_res, 0, 1), MAX_HANDLETSSTR_SIZE); PQclear(p_res); /* clear old res before a new query */ /* check the nlink value of the entry to be updated */ paramValues[0] = handleidparent_str; paramValues[1] = handletsparent_str; p_res = PQexecPrepared(p_conn, "lookupHandleFU", 2, paramValues, NULL, NULL, 0); CheckResult(p_res); found = (PQntuples(p_res) == 1); if(found) { /* we have retrieved the handle information of the bad entry */ nlink = atoi(PQgetvalue(p_res, 0, 4)); PQclear(p_res); /* clear old res before a new query */ /* a Parent entry already exists, we delete it */ st = fsal_posixdb_deleteParent(p_conn, bad_handleid_str, bad_handlets_str, p_parent_directory_handle ? handleidparent_str : handleid_str, p_parent_directory_handle ? handletsparent_str : handlets_str, p_filename ? p_filename->name : "", nlink); if(FSAL_POSIXDB_IS_ERROR(st)) { RollbackTransaction(p_conn, p_res); return st; } } else { /* the Handle line has been deleted */ PQclear(p_res); /* clear old res before a new query */ } /* the bad entry has been deleted. Now we had a new Parent entry */ goto add_new_parent_entry; } else { /* a Parent entry exists with our handle, nothing to do */ PQclear(p_res); } } else { /* add a Parent entry */ PQclear(p_res); add_new_parent_entry: paramValues[0] = p_parent_directory_handle ? handleidparent_str : handleid_str; paramValues[1] = p_parent_directory_handle ? handletsparent_str : handlets_str; paramValues[2] = p_filename ? p_filename->name : ""; paramValues[3] = handleid_str; paramValues[4] = handlets_str; p_res = PQexecPrepared(p_conn, "insertParent", 5, paramValues, NULL, NULL, 0); CheckCommand(p_res); PQclear(p_res); /* XXX : is it possible to have unique key violation ? */ } EndTransaction(p_conn, p_res); ReturnCodeDB(ERR_FSAL_POSIXDB_NOERR, 0); }
/** * @brief Get the handle of a file from a fsal_posixdb_child array, knowing its name * * @param p_context * @param p_parent_dir_handle * Handle of the parent directory * @param p_fsalname * Name of the object * @param p_infofs * Information about the file (taken from the filesystem) to be compared to information stored in database * @param p_children * fsal_posixdb_child array (that contains the entries of the directory stored in the db) * @param p_object_handle * Handle of the file. * * @return * ERR_FSAL_NOERR, if no error * Anothere error code else. */ fsal_status_t fsal_internal_getInfoFromChildrenList(posixfsal_op_context_t * p_context, /* IN */ posixfsal_handle_t * p_parent_dir_handle, /* IN */ fsal_name_t * p_fsalname, /* IN */ fsal_posixdb_fileinfo_t * p_infofs, /* IN */ fsal_posixdb_child * p_children, /* IN */ unsigned int children_count, /* IN */ posixfsal_handle_t * p_object_handle) /* OUT */ { fsal_posixdb_status_t stdb; fsal_status_t st; int cmp = -1; /* when no children is available */ unsigned int count; /* sanity check */ if(!p_context || !p_parent_dir_handle || !p_fsalname || (!p_children && children_count) || !p_object_handle) ReturnCode(ERR_FSAL_FAULT, 0); /* check if the filename is in the list */ for(count = 0; count < children_count; count++) { cmp = FSAL_namecmp(p_fsalname, &(p_children[count].name)); if(!cmp) break; /* maybe a sorted list could give better result */ } switch (cmp) { case 0: /* Entry found : check consistency */ if(fsal_posixdb_consistency_check(&(p_children[count].handle.data.info), p_infofs)) { /* Entry not consistent */ /* Delete the Handle entry, then add a new one (with a Parent entry) */ stdb = fsal_posixdb_deleteHandle(p_context->p_conn, &(p_children[count].handle)); if(FSAL_POSIXDB_IS_ERROR(stdb) && FSAL_IS_ERROR(st = posixdb2fsal_error(stdb))) return st; /* don't break, add a new entry */ } else { memcpy(p_object_handle, &(p_children[count].handle), sizeof(posixfsal_handle_t)); break; } default: /* not found ! Add it */ st = fsal_internal_posixdb_add_entry(p_context->p_conn, p_fsalname, p_infofs, p_parent_dir_handle, p_object_handle); if(FSAL_IS_ERROR(st)) return st; } ReturnCode(ERR_FSAL_NO_ERROR, 0); }
/** * Get a valid path associated to an handle. * The function selects many paths from the DB and return the first valid one. If is_dir is set, then only 1 path will be constructed from the database. */ fsal_status_t fsal_internal_getPathFromHandle(posixfsal_op_context_t * p_context, /* IN */ posixfsal_handle_t * p_handle, /* IN */ int is_dir, /* IN */ fsal_path_t * p_fsalpath, /* OUT */ struct stat *p_buffstat /* OUT */ ) { fsal_status_t status; fsal_posixdb_status_t statusdb; int rc, errsv, count, i; fsal_posixdb_fileinfo_t infofs; fsal_path_t paths[global_fs_info.maxlink]; if(!p_context || !p_handle || !p_fsalpath) ReturnCode(ERR_FSAL_FAULT, 0); /* if there is a path in the posixfsal_handle_t variable, then try to use it instead of querying the database for it */ /* Read the path from the Handle. If it's valid & coherent, then no need to query the database ! */ /* if !p_buffstat, we don't need to check the path */ statusdb = fsal_posixdb_getInfoFromHandle(p_context->p_conn, p_handle, paths, (is_dir ? 1 : global_fs_info.maxlink), &count); if(FSAL_POSIXDB_IS_ERROR(statusdb) && FSAL_IS_ERROR(status = posixdb2fsal_error(statusdb))) return status; /* if !p_buffstat, then we do not stat the path to test if file is valid */ if(p_buffstat) { for(i = 0; i < count; i++) { TakeTokenFSCall(); rc = lstat(paths[i].path, p_buffstat); errsv = errno; ReleaseTokenFSCall(); if(rc) { /* error : delete the bad path from the database */ char dirc[FSAL_MAX_PATH_LEN]; char basec[FSAL_MAX_PATH_LEN]; fsal_path_t parentdir; fsal_name_t filename; posixfsal_handle_t parenthdl; char *dname, *bname; /* split /path/to/filename in /path/to & filename */ strncpy(dirc, paths[i].path, FSAL_MAX_PATH_LEN); strncpy(basec, paths[i].path, FSAL_MAX_PATH_LEN); dname = dirname(dirc); bname = basename(basec); status = FSAL_str2path(dname, FSAL_MAX_PATH_LEN, &parentdir); status = FSAL_str2name(bname, FSAL_MAX_NAME_LEN, &filename); /* get the handle of /path/to */ status = POSIXFSAL_lookupPath(&parentdir, p_context, &parenthdl, NULL); if(!FSAL_IS_ERROR(status)) { statusdb = fsal_posixdb_delete(p_context->p_conn, &parenthdl, &filename, NULL); /* no need to check if there was an error, because it doesn't change the behavior of the function */ } } else { /* no error */ FSAL_pathcpy(p_fsalpath, &(paths[0])); break; } } if(i == count) ReturnCode(ERR_FSAL_STALE, 0); /* check consistency */ status = fsal_internal_posix2posixdb_fileinfo(p_buffstat, &infofs); if(FSAL_IS_ERROR(status)) return status; if(fsal_posixdb_consistency_check(&(p_handle->data.info), &infofs)) { /* not consistent !! */ /* delete the stale handle */ statusdb = fsal_posixdb_deleteHandle(p_context->p_conn, p_handle); if(FSAL_POSIXDB_IS_ERROR(statusdb) && FSAL_IS_ERROR(status = posixdb2fsal_error(statusdb))) return status; ReturnCode(ERR_FSAL_STALE, 0); } } else { /* @TODO : check that there si at liste 1 path */ FSAL_pathcpy(p_fsalpath, &(paths[0])); } ReturnCode(ERR_FSAL_NO_ERROR, 0); }