Ejemplo n.º 1
0
static int traverse_dir (const char *id)
{
    SeafDir *dir;
    GList *p;
    SeafDirent *seaf_dent;

    dir = seaf_fs_manager_get_seafdir (seaf->fs_mgr, id);
    if (!dir) {
        fprintf (stderr, "Failed to read dir %s\n", id);
        return -1;
    }

    for (p = dir->entries; p; p = p->next) {
        seaf_dent = (SeafDirent *)p->data;

        if (S_ISREG(seaf_dent->mode)) {
            printf ("check file %s\n", seaf_dent->name);
            return check_seafile (seaf_dent->id);
        } else if (S_ISDIR(seaf_dent->mode)) {
            printf ("check directory %s\n", seaf_dent->name);
            return traverse_dir (seaf_dent->id);
        }
    }

    seaf_dir_free (dir);
    return 0;
}
Ejemplo n.º 2
0
static int
delete_dir_recursive (const char *repo_id,
                      int repo_version,
                      const char *dir_path,
                      SeafDir *dir,
                      const char *worktree,
                      struct index_state *istate)
{
    GList *ptr;
    SeafDirent *dent;
    char *sub_path;
    SeafDir *sub_dir;

    for (ptr = dir->entries; ptr; ptr = ptr->next) {
        dent = ptr->data;
        sub_path = g_strconcat (dir_path, "/", dent->name, NULL);

        if (S_ISDIR(dent->mode)) {
            if (strcmp(dent->id, EMPTY_SHA1) == 0) {
                delete_path (worktree, sub_path, dent->mode, 0);
            } else {
                sub_dir = seaf_fs_manager_get_seafdir (seaf->fs_mgr,
                                                       repo_id, repo_version,
                                                       dent->id);
                if (!sub_dir) {
                    seaf_warning ("Failed to find dir %s in repo %.8s.\n",
                                  sub_path, repo_id);
                    g_free (sub_path);
                    return -1;
                }

                if (delete_dir_recursive (repo_id, repo_version,
                                          sub_path, sub_dir,
                                          worktree, istate) < 0) {
                    g_free (sub_path);
                    return -1;
                }

                seaf_dir_free (sub_dir);
            }
        } else if (S_ISREG(dent->mode)) {
            struct cache_entry *ce;

            ce = index_name_exists (istate, sub_path, strlen(sub_path), 0);
            if (ce) {
                delete_path (worktree, sub_path, dent->mode, ce->ce_mtime.sec);
            }
        }

        g_free (sub_path);
    }

    char *full_path = g_build_filename (worktree, dir_path, NULL);
    if (seaf_remove_empty_dir (full_path) < 0) {
        seaf_warning ("Failed to remove dir %s: %s.\n", full_path, strerror(errno));
        return -1;
    }

    return 0;
}
Ejemplo n.º 3
0
/*
 * Recursively check fs tree rooted at @dir_id. This function returns when
 * all non-existent or invalid objects have been put into data->fetch_objs.
 */
static void
check_seafdir (CcnetProcessor *processor, const char *dir_id)
{
    SeafileGetfsProc *proc = (SeafileGetfsProc *)processor;
    USE_PRIV;
    SeafDir *dir = NULL;
    GList *ptr;
    SeafDirent *dent;

    if (!seaf_fs_manager_object_exists(seaf->fs_mgr, dir_id)) {
        priv->fetch_objs = g_list_prepend (priv->fetch_objs, g_strdup(dir_id));
        return;
    }

    dir = seaf_fs_manager_get_seafdir (seaf->fs_mgr, dir_id);
    if (!dir) {
        /* corrupt dir object */
        priv->fetch_objs = g_list_prepend (priv->fetch_objs, g_strdup(dir_id));
        return;
    }

    for (ptr = dir->entries; ptr; ptr = ptr->next) {
        dent = ptr->data;

        /* Don't check objects that have been checked before. */
        if (g_hash_table_lookup (priv->fs_objects, dent->id))
            continue;

        g_hash_table_insert (priv->fs_objects, g_strdup(dent->id), (gpointer)1);

        if (!seaf_fs_manager_object_exists(seaf->fs_mgr, dent->id)) {
            priv->fetch_objs = g_list_prepend (priv->fetch_objs, g_strdup(dent->id));
            continue;
        }

        if (S_ISDIR(dent->mode)) {
            check_seafdir (processor, dent->id);
        } else if (S_ISREG (dent->mode) && proc->tx_task->is_clone) {
            /* Only check seafile object integrity when clone.
             * This is for the purpose of recovery.
             * In ordinary sync, checking every file object's integrity would
             * take too much CPU time.
             */
            gboolean ok;
            gboolean err = FALSE;
            ok = seaf_fs_manager_verify_seafile (seaf->fs_mgr, dent->id, TRUE, &err);
            if (!ok && !err) {
                seaf_warning ("File object %.8s is corrupt, recover from server.\n",
                              dent->id);
                priv->fetch_objs = g_list_prepend (priv->fetch_objs, g_strdup(dent->id));
            }
        }
    }

    seaf_dir_free (dir);
}
Ejemplo n.º 4
0
void
wt_status_collect_changes_index (struct index_state *index,
                                 GList **results,
                                 SeafRepo *repo)
{
    SeafFSManager *fs_mgr;
    SeafCommit *head;
    int pos = 0;
    DiffEntry *de;

    fs_mgr = repo->manager->seaf->fs_mgr;
    head = seaf_commit_manager_get_commit (seaf->commit_mgr,
                                           repo->id, repo->version,
                                           repo->head->commit_id);
    if (!head) {
        seaf_warning ("Failed to get commit %s.\n", repo->head->commit_id);
        return;
    }

    mark_all_ce_unused (index);

    /* if repo is initial, we don't need to check index changes */
    if (strncmp(EMPTY_SHA1, head->root_id, 40) != 0) {
        SeafDir *root;

        /* call diff_index to get status */
        root = seaf_fs_manager_get_seafdir (fs_mgr,
                                            repo->id,
                                            repo->version,
                                            head->root_id);
        if (!root) {
            seaf_warning ("Failed to get root %s.\n", head->root_id);
            seaf_commit_unref (head);
            return;
        }

        if (diff_index(repo->id, repo->version, index, root, results) < 0)
            g_warning("diff index failed\n");
        seaf_dir_free (root);
        seaf_commit_unref (head);
        return;
    }
    seaf_commit_unref (head);

    while (1) {
        struct cache_entry *ce = next_cache_entry(index, &pos);

        if (!ce || ce_stage(ce))
            break;

        ce->ce_flags |= CE_UNPACKED;
        de = diff_entry_new (DIFF_TYPE_INDEX, DIFF_STATUS_ADDED, ce->sha1, ce->name);
        *results = g_list_prepend (*results, de);
    }
}
Ejemplo n.º 5
0
static int get_files_dirs_recursive(struct merge_options *o, SeafDir *tree,
                                    char *base, int baselen)
{
    GList *p;
    char *path;
    int ret = 0;

    for (p = tree->entries; p; p = p->next) {
        SeafDirent *dent = (SeafDirent *)p->data;
        SeafDir *subdir;
        int new_baselen;
        int pathlen;
        switch (S_IFMT & dent->mode) {
        case S_IFREG:
            pathlen = baselen + dent->name_len + 1;
            path = malloc(pathlen);
            snprintf(path, pathlen, "%s%s", base, dent->name);
            g_hash_table_replace(o->current_file_set, path, path);
            break;
        case S_IFDIR:
            /* Ignore empty dirs. */
            if (memcmp (dent->id, EMPTY_SHA1, 40) == 0)
                break;

            pathlen = baselen + dent->name_len + 1;
            path = malloc(pathlen);
            snprintf(path, pathlen, "%s%s", base, dent->name);
            g_hash_table_replace(o->current_directory_set, path, path);

            snprintf(base + baselen, SEAF_PATH_MAX, "%s/", dent->name);
            new_baselen = baselen + dent->name_len + 1;
            subdir = seaf_fs_manager_get_seafdir(seaf->fs_mgr, dent->id);
            if (!subdir) {
                g_warning("Failed to get dir %s\n", dent->id);
                return -1;
            }
            ret = get_files_dirs_recursive(o, subdir, base, new_baselen);
            base[baselen] = 0;
            break;
        case S_IFLNK:
            break;
        default:
            break;
        }
    }

    return ret;
}
Ejemplo n.º 6
0
static int
check_object (CcnetProcessor *processor)
{
    USE_PRIV;
    char *obj_id;
    SeafDir *dir;
    static int i = 0;

    request_object_batch_begin(priv);

    /* process inspect queue */
    /* Note: All files in a directory must be checked in an iteration,
     * so we may send out more items than REQUEST_THRESHOLD */
    while (g_hash_table_size (priv->fs_objects) < MAX_NUM_UNREVD) {
        obj_id = (char *) g_queue_pop_head (priv->inspect_queue);
        if (obj_id == NULL)
            break;
        if (!seaf_fs_manager_object_exists(seaf->fs_mgr, obj_id)) {
            request_object_batch (processor, priv, obj_id);
        } else {
            dir = seaf_fs_manager_get_seafdir (seaf->fs_mgr, obj_id);
            if (!dir) {
                /* corrupt dir object */
                request_object_batch (processor, priv, obj_id);
            } else {
                check_seafdir(processor, dir);
                seaf_dir_free (dir);
            }
        }
        g_free (obj_id);        /* free the memory */
    }

    request_object_batch_flush (processor, priv);

    /* check end condition */
    if (i%10 == 0)
        seaf_debug ("[getfs] pending objects num: %d\n", priv->pending_objects);
    ++i;

    if (priv->pending_objects == 0 && g_queue_is_empty(priv->inspect_queue)) {
        ccnet_processor_send_update (processor, SC_END, SS_END, NULL, 0);
        ccnet_processor_done (processor, TRUE);
        return FALSE;
    } else
        return TRUE;
}
Ejemplo n.º 7
0
Archivo: fsck.c Proyecto: rptec/seafile
static void
export_repo_files_recursive (const char *repo_id,
                             const char *id,
                             const char *parent_dir)
{
    SeafDir *dir;
    GList *p;
    SeafDirent *seaf_dent;
    char *path;

    SeafFSManager *mgr = seaf->fs_mgr;
    int version = 1;

    dir = seaf_fs_manager_get_seafdir (mgr, repo_id, version, id);
    if (!dir) {
        return;
    }

    for (p = dir->entries; p; p = p->next) {
        seaf_dent = p->data;
        path = g_build_filename (parent_dir, seaf_dent->name, NULL);

        if (S_ISREG(seaf_dent->mode)) {
            // create file
            create_file (repo_id, seaf_dent->id, path);
        } else if (S_ISDIR(seaf_dent->mode)) {
            if (g_mkdir (path, 0777) < 0) {
                seaf_warning ("Failed to mkdir %s: %s.\n", path,
                              strerror (errno));
                g_free (path);
                continue;
            } else {
                seaf_message ("Export dir %s.\n", path);
            }

            export_repo_files_recursive (repo_id, seaf_dent->id, path);
        }
        g_free (path);
    }

    seaf_dir_free (dir);
}
Ejemplo n.º 8
0
GList *
seaf_repo_manager_list_dir_with_perm (SeafRepoManager *mgr,
                                      const char *repo_id,
                                      const char *dir_path,
                                      const char *dir_id,
                                      const char *user,
                                      int offset,
                                      int limit,
                                      GError **error)
{
    SeafRepo *repo;
    char *perm = NULL;
    SeafDir *dir;
    SeafDirent *dent;
    SeafileDirent *d;
    GList *res = NULL;
    GList *p;

    if (!repo_id || !is_uuid_valid(repo_id) || dir_id == NULL || !user) {
        g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_BAD_DIR_ID, "Bad dir id");
        return NULL;
    }

    perm = seaf_repo_manager_check_permission (mgr, repo_id, user, error);
    if (!perm) {
        if (*error == NULL)
            g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_BAD_ARGS, "Access denied");
        return NULL;
    }

    repo = seaf_repo_manager_get_repo (seaf->repo_mgr, repo_id);
    if (!repo) {
        g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_BAD_ARGS, "Bad repo id");
        g_free (perm);
        return NULL;
    }

    dir = seaf_fs_manager_get_seafdir (seaf->fs_mgr,
                                       repo->store_id, repo->version, dir_id);
    if (!dir) {
        g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_BAD_DIR_ID, "Bad dir id");
        seaf_repo_unref (repo);
        g_free (perm);
        return NULL;
    }

    dir->entries = g_list_sort (dir->entries, comp_dirent_func);

    if (offset < 0) {
        offset = 0;
    }

    int index = 0;
    for (p = dir->entries; p != NULL; p = p->next, index++) {
        if (index < offset) {
            continue;
        }

        if (limit > 0) {
            if (index >= offset + limit)
                break;
        }

        dent = p->data;
        d = g_object_new (SEAFILE_TYPE_DIRENT,
                          "obj_id", dent->id,
                          "obj_name", dent->name,
                          "mode", dent->mode,
                          "version", dent->version,
                          "mtime", dent->mtime,
                          "size", dent->size,
                          "permission", perm,
                          NULL);
        res = g_list_prepend (res, d);
    }

    seaf_dir_free (dir);
    seaf_repo_unref (repo);
    g_free (perm);
    res = g_list_reverse (res);
    return res;
}
Ejemplo n.º 9
0
/*
 * Merge the commits h1 and h2, return merged tree root id
 * and a flag indicating the cleanness of the merge.
 * Return 0 if merge is done (no matter clean or not); -1 otherwise.
 */
int merge_recursive(struct merge_options *o,
                    const char *h1_root,
                    const char *h2_root,
                    const char *ca_root,
                    int *clean,
                    char **root_id)
{
    SeafDir *head, *remote, *common;
    int code, ret = 0;
    struct unpack_trees_options opts;
    char *error = NULL;

    *clean = 1;

    head = seaf_fs_manager_get_seafdir (seaf->fs_mgr, h1_root);
    remote = seaf_fs_manager_get_seafdir (seaf->fs_mgr, h2_root);
    common = seaf_fs_manager_get_seafdir (seaf->fs_mgr, ca_root);
    if (!head || !remote || !common) {
        g_warning ("Invalid commits!\n");
        return -1;
    }

    /* Get merged index. */
    code = seafile_merge_trees(o, &opts, common, head, remote, &error);

    if (code != 0) {
        ret = -1;
        goto out;
    }

    /* If only collect blocks, return success. */
    if (o->collect_blocks_only) {
        process_unmerged_entries (o, head, remote);
        goto out;
    }

    /* Update worktree. */
    /* On windows, we have to Check if any files need to be updated
     * are locked by other program (e.g. Office). If no file is locked,
     * update worktree; otherwise just quit.
     * 
     * Note that if we're recovering merge on startup, we need to update
     * worktree no matter files are locked or not, since we cannot retry
     * this operation. This will produce more confusing results, but
     * it doesn't hurt data integrity.
     */
#ifdef WIN32
    if (o->recover_merge || o->force_merge ||
        !files_locked_on_windows (o->index, o->worktree)) {
        update_worktree (&opts, o->recover_merge,
                         o->remote_head, o->branch2, NULL);
        *clean = process_unmerged_entries (o, head, remote);
    } else {
        /* Don't update anything. */
        g_debug ("[merge] files are locked, quit merge now.\n");
        ret = -1;
        goto out;
    }
#else
    update_worktree (&opts, o->recover_merge,
                     o->remote_head, o->branch2, NULL);
    *clean = process_unmerged_entries (o, head, remote);
#endif

    if (*clean)
        *root_id = write_tree_from_memory(o);

out:
    seaf_dir_free (head);
    seaf_dir_free (remote);
    seaf_dir_free (common);
    return ret;
}
Ejemplo n.º 10
0
Archivo: fsck.c Proyecto: rptec/seafile
static char*
fsck_check_dir_recursive (const char *id, const char *parent_dir, FsckData *fsck_data)
{
    SeafDir *dir;
    SeafDir *new_dir;
    GList *p;
    SeafDirent *seaf_dent;
    char *dir_id = NULL;
    char *path = NULL;
    gboolean io_error = FALSE;

    SeafFSManager *mgr = seaf->fs_mgr;
    char *store_id = fsck_data->repo->store_id;
    int version = fsck_data->repo->version;
    gboolean is_corrupted = FALSE;

    dir = seaf_fs_manager_get_seafdir (mgr, store_id, version, id);

    for (p = dir->entries; p; p = p->next) {
        seaf_dent = p->data;
        io_error = FALSE;

        if (S_ISREG(seaf_dent->mode)) {
            path = g_strdup_printf ("%s%s", parent_dir, seaf_dent->name);
            if (!path) {
                seaf_warning ("Out of memory, stop to run fsck for repo %.8s.\n",
                              fsck_data->repo->id);
                goto out;
            }
            if (!fsck_verify_seafobj (store_id, version,
                                      seaf_dent->id, &io_error,
                                      VERIFY_FILE, fsck_data->repair)) {
                if (io_error) {
                    g_free (path);
                    goto out;
                }
                is_corrupted = TRUE;
                if (fsck_data->repair) {
                    seaf_message ("File %s(%.8s) is corrupted, recreate an empty file.\n",
                                  path, seaf_dent->id);
                } else {
                    seaf_message ("File %s(%.8s) is corrupted.\n",
                                  path, seaf_dent->id);
                }
                // file corrupted, set it empty
                memcpy (seaf_dent->id, EMPTY_SHA1, 40);
                seaf_dent->size = 0;
            } else {
                if (check_blocks (seaf_dent->id, fsck_data, &io_error) < 0) {
                    if (io_error) {
                        g_free (path);
                        goto out;
                    }
                    is_corrupted = TRUE;
                    if (fsck_data->repair) {
                        seaf_message ("File %s(%.8s) is corrupted, recreate an empty file.\n",
                                      path, seaf_dent->id);
                    } else {
                        seaf_message ("File %s(%.8s) is corrupted.\n",
                                      path, seaf_dent->id);
                    }
                    // file corrupted, set it empty
                    memcpy (seaf_dent->id, EMPTY_SHA1, 40);
                    seaf_dent->size = 0;
                }
            }
            g_free (path);
        } else if (S_ISDIR(seaf_dent->mode)) {
            path = g_strdup_printf ("%s%s/", parent_dir, seaf_dent->name);
            if (!path) {
                seaf_warning ("Out of memory, stop to run fsck for repo %.8s.\n",
                              fsck_data->repo->id);
                goto out;
            }
            if (!fsck_verify_seafobj (store_id, version,
                                      seaf_dent->id, &io_error,
                                      VERIFY_DIR, fsck_data->repair)) {
                if (io_error) {
                    g_free (path);
                    goto out;
                }
                if (fsck_data->repair) {
                    seaf_message ("Dir %s(%.8s) is corrupted, recreate an empty dir.\n",
                                  path, seaf_dent->id);
                } else {
                    seaf_message ("Dir %s(%.8s) is corrupted.\n",
                                  path, seaf_dent->id);
                }
                is_corrupted = TRUE;
                // dir corrupted, set it empty
                memcpy (seaf_dent->id, EMPTY_SHA1, 40);
            } else {
               dir_id = fsck_check_dir_recursive (seaf_dent->id, path, fsck_data);
               if (dir_id == NULL) {
                   // IO error
                   g_free (path);
                   goto out;
               }
               if (strcmp (dir_id, seaf_dent->id) != 0) {
                   is_corrupted = TRUE;
                   // dir corrupted, set it to new dir_id
                   memcpy (seaf_dent->id, dir_id, 41);
               }
               g_free (dir_id);
           }
           g_free (path);
        }
    }

    if (is_corrupted) {
        new_dir = seaf_dir_new (NULL, dir->entries, version);
        if (fsck_data->repair) {
            if (seaf_dir_save (mgr, store_id, version, new_dir) < 0) {
                seaf_warning ("Failed to save dir\n");
                seaf_dir_free (new_dir);
                goto out;
            }
        }
        dir_id = g_strdup (new_dir->dir_id);
        seaf_dir_free (new_dir);
        dir->entries = NULL;
    } else {
        dir_id = g_strdup (dir->dir_id);
    }

out:
    seaf_dir_free (dir);

    return dir_id;
}
Ejemplo n.º 11
0
static int getattr_repo(SeafileSession *seaf,
                        const char *user, const char *repo_id, const char *repo_path,
                        struct stat *stbuf)
{
    SeafRepo *repo = NULL;
    SeafBranch *branch;
    SeafCommit *commit = NULL;
    guint32 mode = 0;
    char *id = NULL;
    int ret = 0;

    repo = seaf_repo_manager_get_repo(seaf->repo_mgr, repo_id);
    if (!repo) {
        seaf_warning ("Failed to get repo %s.\n", repo_id);
        ret = -ENOENT;
        goto out;
    }

    branch = repo->head;
    commit = seaf_commit_manager_get_commit(seaf->commit_mgr, branch->commit_id);
    if (!commit) {
        seaf_warning ("Failed to get commit %.8s.\n", branch->commit_id);
        ret = -ENOENT;
        goto out;
    }

    id = seaf_fs_manager_path_to_obj_id(seaf->fs_mgr, commit->root_id,
                                        repo_path, &mode, NULL);
    if (!id) {
        seaf_warning ("Path %s doesn't exist in repo %s.\n", repo_path, repo_id);
        ret = -ENOENT;
        goto out;
    }

    if (S_ISDIR(mode)) {
        SeafDir *dir;
        GList *l;
        int cnt = 2; /* '.' and '..' */

        dir = seaf_fs_manager_get_seafdir(seaf->fs_mgr, id);
        if (dir) {
            for (l = dir->entries; l; l = l->next)
                cnt++;
        }

        stbuf->st_size += cnt * sizeof(SeafDirent);
        stbuf->st_mode = mode | 0755;
        stbuf->st_nlink = 2;

        seaf_dir_free (dir);
    } else if (S_ISREG(mode)) {
        Seafile *file;

        file = seaf_fs_manager_get_seafile(seaf->fs_mgr, id);
        if (file)
            stbuf->st_size = file->file_size;

        stbuf->st_mode = mode | 0644;
        stbuf->st_nlink = 1;

        seafile_unref (file);
    } else {
        return -ENOENT;
    }

out:
    g_free (id);
    seaf_repo_unref (repo);
    seaf_commit_unref (commit);
    return ret;
}
Ejemplo n.º 12
0
GList *
seaf_repo_manager_list_dir_with_perm (SeafRepoManager *mgr,
                                      const char *repo_id,
                                      const char *dir_path,
                                      const char *dir_id,
                                      const char *user,
                                      int offset,
                                      int limit,
                                      GError **error)
{
    SeafRepo *repo;
    char *perm = NULL;
    SeafDir *dir;
    SeafDirent *dent;
    SeafileDirent *d;
    GList *res = NULL;
    GList *p;

    if (!repo_id || !is_uuid_valid(repo_id) || dir_id == NULL || !user) {
        g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_BAD_DIR_ID, "Bad dir id");
        return NULL;
    }

    perm = seaf_repo_manager_check_permission (mgr, repo_id, user, error);
    if (!perm) {
        if (*error == NULL)
            g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_BAD_ARGS, "Access denied");
        return NULL;
    }

    repo = seaf_repo_manager_get_repo (seaf->repo_mgr, repo_id);
    if (!repo) {
        g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_BAD_ARGS, "Bad repo id");
        g_free (perm);
        return NULL;
    }

    dir = seaf_fs_manager_get_seafdir (seaf->fs_mgr,
                                       repo->store_id, repo->version, dir_id);
    if (!dir) {
        g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_BAD_DIR_ID, "Bad dir id");
        seaf_repo_unref (repo);
        g_free (perm);
        return NULL;
    }

    dir->entries = g_list_sort (dir->entries, comp_dirent_func);

    if (offset < 0) {
        offset = 0;
    }

    int index = 0;
    gboolean is_shared;
    char *cur_path;
    GHashTable *shared_sub_dirs = NULL;

    if (!repo->virtual_info) {
        char *repo_owner = seaf_repo_manager_get_repo_owner (seaf->repo_mgr, repo_id);
        if (repo_owner && strcmp (user, repo_owner) == 0) {
            shared_sub_dirs = seaf_share_manager_get_shared_sub_dirs (seaf->share_mgr,
                                                                      repo->store_id,
                                                                      dir_path);
        }
        g_free (repo_owner);
    }

    for (p = dir->entries; p != NULL; p = p->next, index++) {
        if (index < offset) {
            continue;
        }

        if (limit > 0) {
            if (index >= offset + limit)
                break;
        }

        dent = p->data;
        d = g_object_new (SEAFILE_TYPE_DIRENT,
                          "obj_id", dent->id,
                          "obj_name", dent->name,
                          "mode", dent->mode,
                          "version", dent->version,
                          "mtime", dent->mtime,
                          "size", dent->size,
                          "permission", perm,
                          NULL);

        if (shared_sub_dirs && S_ISDIR(dent->mode)) {
            if (strcmp (dir_path, "/") == 0) {
                cur_path = g_strconcat (dir_path, dent->name, NULL);
            } else {
                cur_path = g_strconcat (dir_path, "/", dent->name, NULL);
            }
            is_shared = g_hash_table_lookup (shared_sub_dirs, cur_path) ? TRUE : FALSE;
            g_free (cur_path);
            g_object_set (d, "is_shared", is_shared, NULL);
        }
        res = g_list_prepend (res, d);
    }

    if (shared_sub_dirs)
        g_hash_table_destroy (shared_sub_dirs);
    seaf_dir_free (dir);
    seaf_repo_unref (repo);
    g_free (perm);
    if (res)
        res = g_list_reverse (res);

    return res;
}