1 | /* fs-util.c : internal utility functions used by both FSFS and BDB back |
---|
2 | * ends. |
---|
3 | * |
---|
4 | * ==================================================================== |
---|
5 | * Copyright (c) 2007, 2009 CollabNet. All rights reserved. |
---|
6 | * |
---|
7 | * This software is licensed as described in the file COPYING, which |
---|
8 | * you should have received as part of this distribution. The terms |
---|
9 | * are also available at http://subversion.tigris.org/license-1.html. |
---|
10 | * If newer versions of this license are posted there, you may use a |
---|
11 | * newer version instead, at your option. |
---|
12 | * |
---|
13 | * This software consists of voluntary contributions made by many |
---|
14 | * individuals. For exact contribution history, see the revision |
---|
15 | * history and logs, available at http://subversion.tigris.org/. |
---|
16 | * ==================================================================== |
---|
17 | */ |
---|
18 | |
---|
19 | #include <string.h> |
---|
20 | |
---|
21 | #include <apr_pools.h> |
---|
22 | #include <apr_strings.h> |
---|
23 | |
---|
24 | #include "svn_fs.h" |
---|
25 | #include "svn_path.h" |
---|
26 | #include "svn_private_config.h" |
---|
27 | |
---|
28 | #include "private/svn_fs_util.h" |
---|
29 | #include "../libsvn_fs/fs-loader.h" |
---|
30 | |
---|
31 | const char * |
---|
32 | svn_fs__canonicalize_abspath(const char *path, apr_pool_t *pool) |
---|
33 | { |
---|
34 | char *newpath; |
---|
35 | int path_len; |
---|
36 | int path_i = 0, newpath_i = 0; |
---|
37 | svn_boolean_t eating_slashes = FALSE; |
---|
38 | |
---|
39 | /* No PATH? No problem. */ |
---|
40 | if (! path) |
---|
41 | return NULL; |
---|
42 | |
---|
43 | /* Empty PATH? That's just "/". */ |
---|
44 | if (! *path) |
---|
45 | return apr_pstrdup(pool, "/"); |
---|
46 | |
---|
47 | /* Now, the fun begins. Alloc enough room to hold PATH with an |
---|
48 | added leading '/'. */ |
---|
49 | path_len = strlen(path); |
---|
50 | newpath = apr_pcalloc(pool, path_len + 2); |
---|
51 | |
---|
52 | /* No leading slash? Fix that. */ |
---|
53 | if (*path != '/') |
---|
54 | { |
---|
55 | newpath[newpath_i++] = '/'; |
---|
56 | } |
---|
57 | |
---|
58 | for (path_i = 0; path_i < path_len; path_i++) |
---|
59 | { |
---|
60 | if (path[path_i] == '/') |
---|
61 | { |
---|
62 | /* The current character is a '/'. If we are eating up |
---|
63 | extra '/' characters, skip this character. Else, note |
---|
64 | that we are now eating slashes. */ |
---|
65 | if (eating_slashes) |
---|
66 | continue; |
---|
67 | eating_slashes = TRUE; |
---|
68 | } |
---|
69 | else |
---|
70 | { |
---|
71 | /* The current character is NOT a '/'. If we were eating |
---|
72 | slashes, we need not do that any more. */ |
---|
73 | if (eating_slashes) |
---|
74 | eating_slashes = FALSE; |
---|
75 | } |
---|
76 | |
---|
77 | /* Copy the current character into our new buffer. */ |
---|
78 | newpath[newpath_i++] = path[path_i]; |
---|
79 | } |
---|
80 | |
---|
81 | /* Did we leave a '/' attached to the end of NEWPATH (other than in |
---|
82 | the root directory case)? */ |
---|
83 | if ((newpath[newpath_i - 1] == '/') && (newpath_i > 1)) |
---|
84 | newpath[newpath_i - 1] = '\0'; |
---|
85 | |
---|
86 | return newpath; |
---|
87 | } |
---|
88 | |
---|
89 | svn_error_t * |
---|
90 | svn_fs__check_fs(svn_fs_t *fs, |
---|
91 | svn_boolean_t expect_open) |
---|
92 | { |
---|
93 | if ((expect_open && fs->fsap_data) |
---|
94 | || ((! expect_open) && (! fs->fsap_data))) |
---|
95 | return SVN_NO_ERROR; |
---|
96 | if (expect_open) |
---|
97 | return svn_error_create(SVN_ERR_FS_NOT_OPEN, 0, |
---|
98 | _("Filesystem object has not been opened yet")); |
---|
99 | else |
---|
100 | return svn_error_create(SVN_ERR_FS_ALREADY_OPEN, 0, |
---|
101 | _("Filesystem object already open")); |
---|
102 | } |
---|
103 | |
---|
104 | char * |
---|
105 | svn_fs__next_entry_name(const char **next_p, |
---|
106 | const char *path, |
---|
107 | apr_pool_t *pool) |
---|
108 | { |
---|
109 | const char *end; |
---|
110 | |
---|
111 | /* Find the end of the current component. */ |
---|
112 | end = strchr(path, '/'); |
---|
113 | |
---|
114 | if (! end) |
---|
115 | { |
---|
116 | /* The path contains only one component, with no trailing |
---|
117 | slashes. */ |
---|
118 | *next_p = 0; |
---|
119 | return apr_pstrdup(pool, path); |
---|
120 | } |
---|
121 | else |
---|
122 | { |
---|
123 | /* There's a slash after the first component. Skip over an arbitrary |
---|
124 | number of slashes to find the next one. */ |
---|
125 | const char *next = end; |
---|
126 | while (*next == '/') |
---|
127 | next++; |
---|
128 | *next_p = next; |
---|
129 | return apr_pstrndup(pool, path, end - path); |
---|
130 | } |
---|
131 | } |
---|
132 | |
---|
133 | svn_fs_path_change2_t * |
---|
134 | svn_fs__path_change2_create(const svn_fs_id_t *node_rev_id, |
---|
135 | svn_fs_path_change_kind_t change_kind, |
---|
136 | apr_pool_t *pool) |
---|
137 | { |
---|
138 | svn_fs_path_change2_t *change; |
---|
139 | |
---|
140 | change = apr_pcalloc(pool, sizeof(*change)); |
---|
141 | change->node_rev_id = node_rev_id; |
---|
142 | change->change_kind = change_kind; |
---|
143 | |
---|
144 | return change; |
---|
145 | } |
---|