]> 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
84     EC_ZERO_LOGSTR(lstat(path, &st), "lstat(%s): %s", path, strerror(errno));
85
86     if (path[0] == '/') {
87         EC_NULL(fpath = bfromcstr(path));
88     } else {
89         switch (S_IFMT & st.st_mode) {
90         case S_IFREG:
91         case S_IFLNK:
92             EC_NULL_LOG(dname = strdup(path));
93             EC_ZERO_LOGSTR(chdir(dirname(dname)), "chdir(%s): %s", dirname, strerror(errno));
94             free(dname);
95             dname = NULL;
96             EC_NULL(fpath = bfromcstr(getcwdpath()));
97             BSTRING_STRIP_SLASH(fpath);
98             EC_ZERO(bcatcstr(fpath, "/"));
99             EC_NULL_LOG(dname = strdup(path));
100             EC_ZERO(bcatcstr(fpath, basename(dname)));
101             break;
102
103         case S_IFDIR:
104             EC_ZERO_LOGSTR(chdir(path), "chdir(%s): %s", path, strerror(errno));
105             EC_NULL(fpath = bfromcstr(getcwdpath()));
106             break;
107
108         default:
109             EC_FAIL;
110         }
111     }
112
113     BSTRING_STRIP_SLASH(fpath);
114
115     /*
116      * Now we have eg:
117      *   fpath:   /Volume/netatalk/dir/bla
118      *   volpath: /Volume/netatalk/
119      * we want: "dir/bla"
120      */
121     int len = strlen(volpath);
122     if (volpath[len-1] != '/')
123         /* in case volpath has no trailing slash */
124         len ++;
125     EC_ZERO(bdelete(fpath, 0, len));
126
127 EC_CLEANUP:
128     if (dname) free(dname);
129     if (cwd != -1) {
130         fchdir(cwd);
131         close(cwd);
132     }
133     if (ret != 0)
134         return NULL;
135     return fpath;
136 }
137
138 /*!
139  * Resolves CNID of a given path
140  *
141  * path might be:
142  * (a) relative:
143  *     "dir/subdir" with cwd: "/afp_volume/topdir"
144  * (b) absolute:
145  *     "/afp_volume/dir/subdir"
146  *
147  * path MUST be pointing inside vol, this is usually the case as vol has been build from
148  * path using loadvolinfo and friends.
149  *
150  * @param cdb     (r) CNID db handle
151  * @param volpath (r) UNIX path of volume
152  * @param path    (r) path, see above
153  * @param did     (w) parent CNID of returned CNID
154  *
155  * @returns CNID of path
156  */
157 cnid_t cnid_for_path(struct _cnid_db *cdb,
158                      const char *volpath,
159                      const char *path,
160                      cnid_t *did)
161 {
162     EC_INIT;
163
164     cnid_t cnid;
165     bstring rpath = NULL;
166     bstring statpath = NULL;
167     struct bstrList *l = NULL;
168     struct stat st;
169
170     cnid = htonl(2);
171
172     EC_NULL(rpath = rel_path_in_vol(path, volpath));
173     EC_NULL(statpath = bfromcstr(volpath));
174     EC_ZERO(bcatcstr(statpath, "/"));
175
176     l = bsplit(rpath, '/');
177     for (int i = 0; i < l->qty ; i++) {
178         *did = cnid;
179
180         EC_ZERO( bconcat(statpath, l->entry[i]) );
181         EC_ZERO( lstat(cfrombstr(statpath), &st) );
182
183         if ((cnid = cnid_add(cdb,
184                              &st,
185                              *did,
186                              cfrombstr(l->entry[i]),
187                              blength(l->entry[i]),
188                              0)) == CNID_INVALID) {
189             EC_FAIL;
190         }
191         EC_ZERO(bcatcstr(statpath, "/"));
192     }
193
194 EC_CLEANUP:
195     bdestroy(rpath);
196     bstrListDestroy(l);
197     bdestroy(statpath);
198     if (ret != 0)
199         return CNID_INVALID;
200
201     return cnid;
202 }