]> arthur.barton.de Git - netatalk.git/blob - libatalk/util/cnid.c
Don't log failed lstat
[netatalk.git] / libatalk / util / cnid.c
1 /*
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.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
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.
17  *
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
28  * SUCH DAMAGE.
29  */
30
31 #ifdef HAVE_CONFIG_H
32 #include "config.h"
33 #endif /* HAVE_CONFIG_H */
34
35 #include <sys/types.h>
36 #include <sys/param.h>
37 #include <sys/stat.h>
38 #include <arpa/inet.h>
39 #include <errno.h>
40 #include <fcntl.h>
41 #include <limits.h>
42 #include <stdio.h>
43 #include <stdlib.h>
44 #include <unistd.h>
45 #include <stdarg.h>
46 #include <string.h>
47 #include <libgen.h>
48
49 #include <atalk/util.h>
50 #include <atalk/cnid.h>
51 #include <atalk/bstrlib.h>
52 #include <atalk/bstradd.h>
53 #include <atalk/logger.h>
54 #include <atalk/errchk.h>
55 #include <atalk/unicode.h>
56
57 /*!
58  * Build path relativ to volume root
59  *
60  * path might be:
61  * (a) relative:
62  *     "dir/subdir" with cwd: "/afp_volume/topdir"
63  * (b) absolute:
64  *     "/afp_volume/dir/subdir"
65  *
66  * @param path     (r) path relative to cwd() or absolute
67  * @param volpath  (r) volume path that path is a subdir of (has been computed in volinfo funcs)
68  *
69  * @returns relative path in new bstring, caller must bdestroy it
70  */
71 bstring rel_path_in_vol(const char *path, const char *volpath)
72 {
73     EC_INIT;
74     int cwd = -1;
75     bstring fpath = NULL;
76     char *dname = NULL;
77     struct stat st;
78
79     if (path == NULL || volpath == NULL)
80         return NULL;
81
82     EC_NEG1_LOG(cwd = open(".", O_RDONLY));
83     EC_ZERO( lstat(path, &st) );
84
85     if (path[0] == '/') {
86         EC_NULL(fpath = bfromcstr(path));
87     } else {
88         switch (S_IFMT & st.st_mode) {
89         case S_IFREG:
90         case S_IFLNK:
91             EC_NULL_LOG(dname = strdup(path));
92             EC_ZERO_LOGSTR(chdir(dirname(dname)), "chdir(%s): %s", dirname, strerror(errno));
93             free(dname);
94             dname = NULL;
95             EC_NULL(fpath = bfromcstr(getcwdpath()));
96             BSTRING_STRIP_SLASH(fpath);
97             EC_ZERO(bcatcstr(fpath, "/"));
98             EC_NULL_LOG(dname = strdup(path));
99             EC_ZERO(bcatcstr(fpath, basename(dname)));
100             break;
101
102         case S_IFDIR:
103             EC_ZERO_LOGSTR(chdir(path), "chdir(%s): %s", path, strerror(errno));
104             EC_NULL(fpath = bfromcstr(getcwdpath()));
105             break;
106
107         default:
108             EC_FAIL;
109         }
110     }
111
112     BSTRING_STRIP_SLASH(fpath);
113
114     /*
115      * Now we have eg:
116      *   fpath:   /Volume/netatalk/dir/bla
117      *   volpath: /Volume/netatalk/
118      * we want: "dir/bla"
119      */
120     int len = strlen(volpath);
121     if (volpath[len-1] != '/')
122         /* in case volpath has no trailing slash */
123         len ++;
124     EC_ZERO(bdelete(fpath, 0, len));
125
126 EC_CLEANUP:
127     if (dname) free(dname);
128     if (cwd != -1) {
129         fchdir(cwd);
130         close(cwd);
131     }
132     if (ret != 0)
133         return NULL;
134     return fpath;
135 }
136
137 /*!
138  * Resolves CNID of a given path
139  *
140  * path might be:
141  * (a) relative:
142  *     "dir/subdir" with cwd: "/afp_volume/topdir"
143  * (b) absolute:
144  *     "/afp_volume/dir/subdir"
145  *
146  * path MUST be pointing inside vol, this is usually the case as vol has been build from
147  * path using loadvolinfo and friends.
148  *
149  * @param cdb     (r) CNID db handle
150  * @param volpath (r) UNIX path of volume
151  * @param path    (r) path, see above
152  * @param did     (w) parent CNID of returned CNID
153  *
154  * @returns CNID of path
155  */
156 cnid_t cnid_for_path(struct _cnid_db *cdb,
157                      const char *volpath,
158                      const char *path,
159                      cnid_t *did)
160 {
161     EC_INIT;
162
163     cnid_t cnid;
164     bstring rpath = NULL;
165     bstring statpath = NULL;
166     struct bstrList *l = NULL;
167     struct stat st;
168
169     cnid = htonl(2);
170
171     EC_NULL(rpath = rel_path_in_vol(path, volpath));
172     EC_NULL(statpath = bfromcstr(volpath));
173     EC_ZERO(bcatcstr(statpath, "/"));
174
175     l = bsplit(rpath, '/');
176     for (int i = 0; i < l->qty ; i++) {
177         *did = cnid;
178
179         EC_ZERO( bconcat(statpath, l->entry[i]) );
180         EC_ZERO( lstat(cfrombstr(statpath), &st) );
181
182         if ((cnid = cnid_add(cdb,
183                              &st,
184                              *did,
185                              cfrombstr(l->entry[i]),
186                              blength(l->entry[i]),
187                              0)) == CNID_INVALID) {
188             EC_FAIL;
189         }
190         EC_ZERO(bcatcstr(statpath, "/"));
191     }
192
193 EC_CLEANUP:
194     bdestroy(rpath);
195     bstrListDestroy(l);
196     bdestroy(statpath);
197     if (ret != 0)
198         return CNID_INVALID;
199
200     return cnid;
201 }