Major manpage overhaul.
[usmb.git] / usmb_file.c
blob1f5a341b8998f557645ba95b0c0f5d68d774a751
1 /* usmb - mount SMB shares via FUSE and Samba
2 * Copyright (C) 2006-2009 Geoff Johnstone
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 3 as
6 * published by the Free Software Foundation.
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 #include "config.h"
18 #include <sys/time.h> // struct timeval needed by libsmbclient.h
19 #include <libsmbclient.h>
20 #include "samba3x-compat.h"
21 #include <limits.h>
22 #include <assert.h>
23 #include <fuse.h>
24 #include <errno.h>
25 #include <stdbool.h>
26 #include <stddef.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include "usmb_file.h"
31 #include "usmb.h"
32 #include "utils.h"
35 // Samba gets st_nlink wrong for directories.
36 static bool fix_nlink (const char *url, struct stat *st)
38 assert (NULL != url);
39 assert (NULL != st);
41 if (!S_ISDIR (st->st_mode))
42 return true;
44 SMBCFILE *file = smbc_getFunctionOpendir (ctx) (ctx, url);
45 if (NULL == file)
46 return false;
48 // st->st_nlink = 2;
49 st->st_nlink = 0;
50 errno = ERANGE;
52 struct smbc_dirent *dirent;
54 while (NULL != (dirent = smbc_getFunctionReaddir (ctx) (ctx, file)))
55 if (SMBC_DIR == dirent->smbc_type)
56 if (INT_MAX == st->st_nlink++)
57 break;
59 (void)smbc_getFunctionClosedir (ctx) (ctx, file);
60 return (NULL == dirent);
64 int usmb_getattr (const char *filename, struct stat *st)
66 char *url = make_url (filename);
67 if (NULL == url)
68 return -ENOMEM;
70 DEBUG (fprintf (stderr, "stat (%s)\n", url));
72 int ret = smbc_getFunctionStat (ctx) (ctx, url, st);
74 if ((0 > ret) || !fix_nlink (url, st))
75 ret = -errno;
77 free (url);
78 return ret;
82 int usmb_fgetattr (const char *filename UNUSED, struct stat *st,
83 struct fuse_file_info *fi)
85 SMBCFILE *file = fd_to_smbcfile (fi->fh);
86 DEBUG (fprintf (stderr, "fgetattr (%s, %p)\n", filename, (void *)file));
88 if (0 > smbc_getFunctionFstat (ctx) (ctx, file, st))
89 return -errno;
91 if (S_ISDIR (st->st_mode))
93 char *url = make_url (filename);
94 if (NULL == url)
95 return -ENOMEM;
97 bool ok = fix_nlink (url, st);
98 free_errno (url);
100 if (!ok)
101 return -errno;
104 return 0;
108 int usmb_unlink (const char *filename)
110 char *url = make_url (filename);
111 if (NULL == url)
112 return -ENOMEM;
114 DEBUG (fprintf (stderr, "unlink (%s)\n", url));
115 int ret = (0 > smbc_getFunctionUnlink (ctx) (ctx, url)) ? -errno : 0;
116 free (url);
117 return ret;
121 int usmb_open (const char *filename, struct fuse_file_info *fi)
123 char *url = make_url (filename);
124 if (NULL == url)
125 return -ENOMEM;
127 DEBUG (fprintf (stderr, "open (%s, %d)", url, fi->flags));
128 SMBCFILE *file = smbc_getFunctionOpen (ctx) (ctx, url, fi->flags, 0);
129 DEBUG (fprintf (stderr, " = %p\n", (void *)file));
131 int ret = (NULL == file) ? -errno : 0;
132 free (url);
133 fi->fh = smbcfile_to_fd (file);
135 return ret;
139 int usmb_release (const char *filename UNUSED, struct fuse_file_info *fi)
141 SMBCFILE *file = fd_to_smbcfile (fi->fh);
142 DEBUG (fprintf (stderr, "release (%s, %p)\n", filename, (void *)file));
143 return (0 > smbc_getFunctionClose (ctx) (ctx, file)) ? -errno : 0;
147 int usmb_read (const char *filename UNUSED, char *buff, size_t len, off_t off,
148 struct fuse_file_info *fi)
150 assert (32768 >= len);
152 SMBCFILE *file = fd_to_smbcfile (fi->fh);
153 DEBUG (fprintf (stderr, "read (%p, %p, %u, %lld) ",
154 (void *)file, buff, len, off));
156 if (0 > smbc_getFunctionLseek (ctx) (ctx, file, off, SEEK_SET))
158 fprintf (stderr, "- seek failed: %d\n", -errno);
159 return -errno;
162 int bytes = smbc_getFunctionRead (ctx) (ctx, file, buff, len);
163 DEBUG (fprintf (stderr, "= %d\n", bytes));
164 return (0 > bytes) ? -errno : (int)bytes;
168 int usmb_write (const char *filename UNUSED, const char *buff, size_t len,
169 off_t off, struct fuse_file_info *fi)
171 SMBCFILE *file = fd_to_smbcfile (fi->fh);
172 DEBUG (fprintf (stderr, "write (%p, %p, len=%u, off=%lld) ",
173 (void *)file, buff, len, off));
175 if (0 > smbc_getFunctionLseek (ctx) (ctx, file, off, SEEK_SET))
176 return -errno;
178 size_t written = 0;
179 int bytes = 0;
181 // No idea whether Windows servers don't like > 32768 byte writes
182 // (cf. usmb_read), but taking no chances...
184 const smbc_write_fn write_fn = smbc_getFunctionWrite (ctx);
186 while (written < len)
188 bytes = write_fn (ctx, file, (char *)buff, (len > 32768) ? 32768 : len);
189 if (0 > bytes)
190 break;
192 written += bytes;
193 buff += bytes;
195 // avoids infinite loops
196 if (0 == bytes)
197 break;
200 DEBUG (fprintf (stderr, "= %d\n", (0 > bytes) ? -errno : (int)written));
201 return (0 > bytes) ? -errno : (int)written;
205 int usmb_create (const char *filename, mode_t mode, struct fuse_file_info *fi)
207 char *url = make_url (filename);
208 if (NULL == url)
209 return -ENOMEM;
211 DEBUG (fprintf (stderr, "creat (%s)", url));
213 SMBCFILE *file = smbc_getFunctionCreat (ctx) (ctx, url, mode);
214 DEBUG (fprintf (stderr, " = %p\n", (void *)file));
215 int ret = (NULL == file) ? -errno : 0;
216 fi->fh = smbcfile_to_fd (file);
218 free (url);
219 return ret;
223 int usmb_rename (const char *from, const char *to)
225 char *fromurl = make_url (from);
226 if (NULL == fromurl)
227 return -ENOMEM;
229 char *tourl = make_url (to);
230 if (NULL == tourl)
232 free (fromurl);
233 return -ENOMEM;
236 DEBUG (fprintf (stderr, "rename (%s, %s)\n", fromurl, tourl));
237 int ret =
238 (0 > smbc_getFunctionRename (ctx) (ctx, fromurl, ctx, tourl)) ? -errno : 0;
239 free (tourl);
240 free (fromurl);
241 return ret;
245 int usmb_utime (const char *filename, struct utimbuf *utb)
247 struct utimbuf tmp_utb;
249 if (NULL == utb)
251 for (;;)
253 time_t now = time (NULL);
254 if ((time_t)-1 != now)
256 tmp_utb.actime = tmp_utb.modtime = now;
257 break;
260 if (EINTR != errno)
261 return -errno;
264 utb = &tmp_utb;
267 char *url = make_url (filename);
268 if (NULL == url)
269 return -ENOMEM;
271 struct timeval tv[2] = {
272 { .tv_sec = utb->actime, .tv_usec = 0 },
273 { .tv_sec = utb->modtime, .tv_usec = 0 },
276 DEBUG (fprintf (stderr, "utime (%s)\n", url));
277 int ret = (0 > smbc_getFunctionUtimes (ctx) (ctx, url, tv)) ? -errno : 0;
278 free (url);
279 return ret;
283 #if 0
284 Samba defines utimes as taking struct timevals rather than timespecs.
285 int usmb_utimes (const char *filename, const struct timespec ts[2])
287 char *url = make_url (filename);
288 if (NULL == url)
289 return -ENOMEM;
291 DEBUG (fprintf (stderr, "utimes (%s)\n", url));
292 int ret = (0 > ctx->utimes (ctx, url, ts)) ? -errno : 0;
293 free (url);
294 return ret;
296 #endif
299 int usmb_chmod (const char *filename, mode_t mode)
301 char *url = make_url (filename);
302 if (NULL == url)
303 return -ENOMEM;
305 DEBUG (fprintf (stderr, "chmod (%s, %u)\n", url, mode));
306 int ret = (0 > smbc_getFunctionChmod (ctx) (ctx, url, mode)) ? -errno : 0;
307 free (url);
308 return ret;
312 int usmb_truncate (const char *filename, off_t offset)
314 char *url = make_url (filename);
315 if (NULL == url)
316 return -ENOMEM;
318 SMBCFILE *file = smbc_getFunctionOpen (ctx) (ctx, url, O_WRONLY, 0);
319 if (NULL == file)
321 int ret = -errno;
322 free (url);
323 return ret;
326 int ret = compat_truncate (filename, file, offset);
328 smbc_getFunctionClose (ctx) (ctx, file);
329 free (url);
330 return ret;
334 int usmb_ftruncate (const char *path, off_t size,
335 struct fuse_file_info *fi)
337 return compat_truncate (path, fd_to_smbcfile (fi->fh), size);