2 * Copyright (c) 2009 Frank Lahm <franklahm@gmail.com>
3 * Copyright (c) 1991, 1993, 1994
4 * The Regents of the University of California. All rights reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 4. Neither the name of the University nor the names of its contributors
15 * may be used to endorse or promote products derived from this software
16 * without specific prior written permission.
18 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 #endif /* HAVE_CONFIG_H */
35 #include <sys/types.h>
36 #include <sys/param.h>
51 #ifdef HAVE_SOLARIS_ACLS
53 #endif /* HAVE_SOLARIS_ACLS */
55 #ifdef HAVE_POSIX_ACLS
56 #include <sys/types.h>
58 #endif /* HAVE_POSIX_ACLS */
60 #include <atalk/util.h>
61 #include <atalk/cnid.h>
62 #include <atalk/volinfo.h>
63 #include <atalk/bstrlib.h>
64 #include <atalk/bstradd.h>
65 #include <atalk/logger.h>
66 #include <atalk/errchk.h>
67 #include <atalk/unicode.h>
71 int log_verbose; /* Logging flag */
73 void _log(enum logtype lt, char *fmt, ...)
76 static char logbuffer[1024];
79 if ( (lt == STD) || (log_verbose == 1)) {
81 len = vsnprintf(logbuffer, 1023, fmt, args);
85 printf("%s\n", logbuffer);
90 * Load volinfo and initialize struct vol
92 * Only opens "dbd" volumes !
94 * @param path (r) path to evaluate
95 * @param vol (rw) structure to initialize
97 * @returns 0 on success, exits on error
99 int openvol(const char *path, afpvol_t *vol)
103 memset(vol, 0, sizeof(afpvol_t));
105 /* try to find a .AppleDesktop/.volinfo */
106 if (loadvolinfo((char *)path, &vol->volinfo) != 0)
109 if (STRCMP(vol->volinfo.v_cnidscheme, != , "dbd"))
110 ERROR("\"%s\" isn't a \"dbd\" CNID volume!", vol->volinfo.v_path);
112 if (vol_load_charsets(&vol->volinfo) == -1)
113 ERROR("Error loading charsets!");
115 /* Sanity checks to ensure we can touch this volume */
116 if (vol->volinfo.v_adouble != AD_VERSION2)
117 ERROR("Unsupported adouble versions: %u", vol->volinfo.v_adouble);
119 if (vol->volinfo.v_vfs_ea != AFPVOL_EA_SYS)
120 ERROR("Unsupported Extended Attributes option: %u", vol->volinfo.v_vfs_ea);
122 /* initialize sufficient struct vol for VFS initialisation */
123 vol->volume.v_adouble = AD_VERSION2;
124 vol->volume.v_vfs_ea = AFPVOL_EA_SYS;
125 initvol_vfs(&vol->volume);
127 if ((vol->volinfo.v_flags & AFPVOL_NODEV))
128 flags |= CNID_FLAG_NODEV;
130 if ((vol->volume.v_cdb = cnid_open(vol->volinfo.v_dbpath,
134 vol->volinfo.v_dbd_host,
135 vol->volinfo.v_dbd_port)) == NULL)
136 ERROR("Cant initialize CNID database connection for %s", vol->volinfo.v_path);
138 cnid_getstamp(vol->volume.v_cdb,
140 sizeof(vol->db_stamp));
145 void closevol(afpvol_t *vol)
147 if (vol->volume.v_cdb)
148 cnid_close(vol->volume.v_cdb);
150 memset(vol, 0, sizeof(afpvol_t));
154 Taken form afpd/desktop.c
156 char *utompath(const struct volinfo *volinfo, const char *upath)
158 static char mpath[ MAXPATHLEN + 2]; /* for convert_charset dest_len parameter +2 */
161 uint16_t flags = CONV_IGNORE | CONV_UNESCAPEHEX;
169 outlen = strlen(upath);
171 if ((volinfo->v_casefold & AFPVOL_UTOMUPPER))
172 flags |= CONV_TOUPPER;
173 else if ((volinfo->v_casefold & AFPVOL_UTOMLOWER))
174 flags |= CONV_TOLOWER;
176 if ((volinfo->v_flags & AFPVOL_EILSEQ)) {
177 flags |= CONV__EILSEQ;
180 /* convert charsets */
181 if ((size_t)-1 == ( outlen = convert_charset(volinfo->v_volcharset,
183 volinfo->v_maccharset,
184 u, outlen, mpath, MAXPATHLEN, &flags)) ) {
185 SLOG("Conversion from %s to %s for %s failed.",
186 volinfo->v_volcodepage, volinfo->v_maccodepage, u);
194 * Build path relativ to volume root
198 * "dir/subdir" with cwd: "/afp_volume/topdir"
200 * "/afp_volume/dir/subdir"
202 * @param path (r) path relative to cwd() or absolute
203 * @param volpath (r) volume path that path is a subdir of (has been computed in volinfo funcs)
205 * @returns relative path in new bstring, caller must bdestroy it
207 static bstring rel_path_in_vol(const char *path, const char *volpath)
211 bstring fpath = NULL;
215 if (path == NULL || volpath == NULL)
218 EC_NEG1_LOG(cwd = open(".", O_RDONLY));
220 EC_ZERO_LOGSTR(lstat(path, &st), "lstat(%s): %s", path, strerror(errno));
221 switch (S_IFMT & st.st_mode) {
225 EC_NULL_LOG(dname = strdup(path));
226 EC_ZERO_LOGSTR(chdir(dirname(dname)), "chdir(%s): %s", dirname, strerror(errno));
229 EC_NULL(fpath = bfromcstr(getcwdpath()));
230 BSTRING_STRIP_SLASH(fpath);
231 EC_ZERO(bcatcstr(fpath, "/"));
232 EC_NULL_LOG(dname = strdup(path));
233 EC_ZERO(bcatcstr(fpath, basename(dname)));
237 EC_ZERO_LOGSTR(chdir(path), "chdir(%s): %s", path, strerror(errno));
238 EC_NULL(fpath = bfromcstr(getcwdpath()));
242 SLOG("special: %s", path);
246 BSTRING_STRIP_SLASH(fpath);
250 * fpath: /Volume/netatalk/dir/bla
251 * volpath: /Volume/netatalk/
254 EC_ZERO(bdelete(fpath, 0, strlen(volpath)));
257 if (dname) free(dname);
268 * Convert dot encoding of basename _in place_
270 * path arg can be "[/][dir/ | ...]filename". It will be converted in place
271 * possible encoding ".file" as ":2efile" which means the result will be
272 * longer then the original which means provide a big enough buffer.
274 * @param svol (r) source volume
275 * @param dvol (r) destinatio volume
276 * @param path (rw) path to convert _in place_
277 * @param buflen (r) size of path buffer (max strlen == buflen -1)
279 * @returns 0 on sucess, -1 on error
281 int convert_dots_encoding(const afpvol_t *svol, const afpvol_t *dvol, char *path, size_t buflen)
283 static charset_t from = (charset_t) -1;
284 static char buf[MAXPATHLEN+2];
285 char *bname = stripped_slashes_basename(path);
286 int pos = bname - path;
289 if ( ! svol->volinfo.v_path) {
290 /* no source volume: escape special chars (eg ':') */
291 from = dvol->volinfo.v_volcharset; /* src = dst charset */
292 flags |= CONV_ESCAPEHEX;
294 from = svol->volinfo.v_volcharset;
297 if ( (svol->volinfo.v_path)
298 && ! (svol->volinfo.v_flags & AFPVOL_USEDOTS)
299 && (dvol->volinfo.v_flags & AFPVOL_USEDOTS)) {
300 /* source is without dots, destination is with */
301 flags |= CONV_UNESCAPEHEX;
302 } else if (! (dvol->volinfo.v_flags & AFPVOL_USEDOTS)) {
303 flags |= CONV_ESCAPEDOTS;
306 int len = convert_charset(from,
307 dvol->volinfo.v_volcharset,
308 dvol->volinfo.v_maccharset,
309 bname, strlen(bname),
315 if (strlcpy(bname, buf, MAXPATHLEN - pos) > MAXPATHLEN - pos)
321 * ResolvesCNID of a given paths
325 * "dir/subdir" with cwd: "/afp_volume/topdir"
327 * "/afp_volume/dir/subdir"
329 * path MUST be pointing inside vol, this is usually the case as vol has been build from
330 * path using loadvolinfo and friends.
332 * @param vol (r) pointer to afpvol_t
333 * @param path (r) path, see above
334 * @param did (rw) parent CNID of returned CNID
336 * @returns CNID of path
338 cnid_t cnid_for_path(const afpvol_t *vol,
345 bstring rpath = NULL;
346 bstring statpath = NULL;
347 struct bstrList *l = NULL;
353 EC_NULL(rpath = rel_path_in_vol(path, vol->volinfo.v_path));
354 EC_NULL(statpath = bfromcstr(vol->volinfo.v_path));
356 l = bsplit(rpath, '/');
357 for (int i = 0; i < l->qty ; i++) {
359 EC_ZERO(bconcat(statpath, l->entry[i]));
360 EC_ZERO_LOGSTR(lstat(cfrombstr(statpath), &st),
361 "lstat(rpath: %s, elem: %s): %s: %s",
362 cfrombstr(rpath), cfrombstr(l->entry[i]),
363 cfrombstr(statpath), strerror(errno));
365 if ((cnid = cnid_add(vol->volume.v_cdb,
368 cfrombstr(l->entry[i]),
369 blength(l->entry[i]),
370 0)) == CNID_INVALID) {
373 EC_ZERO(bcatcstr(statpath, "/"));
387 * Resolves CNID of a given paths parent directory
391 * "dir/subdir" with cwd: "/afp_volume/topdir"
393 * "/afp_volume/dir/subdir"
395 * path MUST be pointing inside vol, this is usually the case as vol has been build from
396 * path using loadvolinfo and friends.
398 * @param vol (r) pointer to afpvol_t
399 * @param path (r) path, see above
400 * @param did (rw) parent CNID of returned CNID
402 * @returns CNID of path
404 cnid_t cnid_for_paths_parent(const afpvol_t *vol,
411 bstring rpath = NULL;
412 bstring statpath = NULL;
413 struct bstrList *l = NULL;
419 EC_NULL(rpath = rel_path_in_vol(path, vol->volinfo.v_path));
420 EC_NULL(statpath = bfromcstr(vol->volinfo.v_path));
422 l = bsplit(rpath, '/');
424 /* only one path element, means parent dir cnid is volume root = 2 */
426 for (int i = 0; i < (l->qty - 1); i++) {
428 EC_ZERO(bconcat(statpath, l->entry[i]));
429 EC_ZERO_LOGSTR(lstat(cfrombstr(statpath), &st),
430 "lstat(rpath: %s, elem: %s): %s: %s",
431 cfrombstr(rpath), cfrombstr(l->entry[i]),
432 cfrombstr(statpath), strerror(errno));
434 if ((cnid = cnid_add(vol->volume.v_cdb,
437 cfrombstr(l->entry[i]),
438 blength(l->entry[i]),
439 0)) == CNID_INVALID) {
442 EC_ZERO(bcatcstr(statpath, "/"));