📄 storage.c
字号:
/* This file is part of GNUnet. (C) 2001, 2002, 2005, 2006 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.*//** * @file util/disk/storage.c * @brief disk IO convenience methods * @author Christian Grothoff */#include "platform.h"#include "gnunet_util_string.h"#include "gnunet_util_disk.h"#if LINUX || CYGWIN#include <sys/vfs.h>#else#ifdef SOMEBSD#include <sys/param.h>#include <sys/mount.h>#else#ifdef OSX#include <sys/param.h>#include <sys/mount.h>#else#ifdef SOLARIS#include <sys/types.h>#include <sys/statvfs.h>#else#ifdef MINGW#define _IFMT 0170000 /* type of file */#define _IFLNK 0120000 /* symbolic link */#define S_ISLNK(m) (((m)&_IFMT) == _IFLNK)#else#error PORT-ME: need to port statfs (how much space is left on the drive?)#endif#endif#endif#endif#endif#ifndef SOMEBSD#ifndef WINDOWS#ifndef OSX#include <wordexp.h>#endif#endif#endiftypedef struct{ struct GNUNET_GE_Context *ectx; unsigned long long total; int include_sym_links;} GetFileSizeData;static intgetSizeRec (const char *filename, const char *dirname, void *ptr){ GetFileSizeData *gfsd = ptr;#ifdef HAVE_STAT64 struct stat64 buf;#else struct stat buf;#endif char *fn; GNUNET_GE_ASSERT (gfsd->ectx, filename != NULL); if ((dirname != NULL) && (strlen (dirname) > 0)) { fn = GNUNET_malloc (strlen (filename) + strlen (dirname) + 3); if (strlen (dirname) > 0) { strcpy (fn, dirname); if (dirname[strlen (dirname) - 1] != DIR_SEPARATOR) strcat (fn, DIR_SEPARATOR_STR); /* add tailing / if needed */ } /* Windows paths don't start with / */#ifndef MINGW else strcpy (fn, DIR_SEPARATOR_STR);#endif if (filename[0] == DIR_SEPARATOR) /* if filename starts with a "/", don't copy it */ strcat (fn, &filename[1]); else strcat (fn, filename); } else fn = GNUNET_strdup (filename);#ifdef HAVE_STAT64 if (0 != STAT64 (fn, &buf)) { GNUNET_GE_LOG_STRERROR_FILE (gfsd->ectx, GNUNET_GE_WARNING | GNUNET_GE_USER | GNUNET_GE_REQUEST, "stat64", fn); GNUNET_free (fn); return GNUNET_SYSERR; }#else if (0 != STAT (fn, &buf)) { GNUNET_GE_LOG_STRERROR_FILE (gfsd->ectx, GNUNET_GE_WARNING | GNUNET_GE_USER | GNUNET_GE_REQUEST, "stat", fn); GNUNET_free (fn); return GNUNET_SYSERR; }#endif if ((!S_ISLNK (buf.st_mode)) || (gfsd->include_sym_links == GNUNET_YES)) gfsd->total += buf.st_size; if ((S_ISDIR (buf.st_mode)) && (0 == ACCESS (fn, X_OK)) && ((!S_ISLNK (buf.st_mode)) || (gfsd->include_sym_links == GNUNET_YES))) { if (GNUNET_SYSERR == GNUNET_disk_directory_scan (gfsd->ectx, fn, &getSizeRec, gfsd)) { GNUNET_free (fn); return GNUNET_SYSERR; } } GNUNET_free (fn); return GNUNET_OK;}/** * Get the size of the file (or directory) * of the given file (in bytes). * * @return GNUNET_SYSERR on error, GNUNET_OK on success */intGNUNET_disk_file_size (struct GNUNET_GE_Context *ectx, const char *filename, unsigned long long *size, int includeSymLinks){ GetFileSizeData gfsd; int ret; GNUNET_GE_ASSERT (ectx, size != NULL); gfsd.ectx = ectx; gfsd.total = 0; gfsd.include_sym_links = includeSymLinks; ret = getSizeRec (filename, "", &gfsd); *size = gfsd.total; return ret;}/** * Get the number of blocks that are left on the partition that * contains the given file (for normal users). * * @param part a file on the partition to check * @return -1 on errors, otherwise the number of free blocks */longGNUNET_disk_get_blocks_available (struct GNUNET_GE_Context *ectx, const char *part){#ifdef SOLARIS struct statvfs buf; if (0 != statvfs (part, &buf)) { GNUNET_GE_LOG_STRERROR_FILE (ectx, GNUNET_GE_WARNING | GNUNET_GE_USER | GNUNET_GE_ADMIN | GNUNET_GE_BULK, "statfs", part); return -1; } return buf.f_bavail;#elif MINGW DWORD dwDummy; DWORD dwBlocks; char szDrive[4]; memcpy (szDrive, part, 3); szDrive[3] = 0; if (!GetDiskFreeSpace (szDrive, &dwDummy, &dwDummy, &dwBlocks, &dwDummy)) { GNUNET_GE_LOG (ectx, GNUNET_GE_WARNING | GNUNET_GE_USER | GNUNET_GE_ADMIN | GNUNET_GE_BULK, _("`%s' failed for drive `%s': %u\n"), "GetDiskFreeSpace", szDrive, GetLastError ()); return -1; } return dwBlocks;#else struct statfs s; if (0 != statfs (part, &s)) { GNUNET_GE_LOG_STRERROR_FILE (ectx, GNUNET_GE_WARNING | GNUNET_GE_USER | GNUNET_GE_ADMIN | GNUNET_GE_BULK, "statfs", part); return -1; } return s.f_bavail;#endif}/** * Test if fil is a directory. * * @return GNUNET_YES if yes, GNUNET_NO if not, GNUNET_SYSERR if it * does not exist */intGNUNET_disk_directory_test (struct GNUNET_GE_Context *ectx, const char *fil){ struct stat filestat; int ret; ret = STAT (fil, &filestat); if (ret != 0) { if (errno != ENOENT) { GNUNET_GE_LOG_STRERROR_FILE (ectx, GNUNET_GE_WARNING | GNUNET_GE_USER | GNUNET_GE_ADMIN | GNUNET_GE_REQUEST, "stat", fil); return GNUNET_SYSERR; } return GNUNET_NO; } if (!S_ISDIR (filestat.st_mode)) return GNUNET_NO; if (ACCESS (fil, R_OK | X_OK) < 0) { GNUNET_GE_LOG_STRERROR_FILE (ectx, GNUNET_GE_WARNING | GNUNET_GE_USER | GNUNET_GE_ADMIN | GNUNET_GE_REQUEST, "access", fil); return GNUNET_SYSERR; } return GNUNET_YES;}/** * Check that fil corresponds to a filename * (of a file that exists and that is not a directory). * @returns GNUNET_YES if yes, GNUNET_NO if not a file, GNUNET_SYSERR if something * else (will print an error message in that case, too). */intGNUNET_disk_file_test (struct GNUNET_GE_Context *ectx, const char *fil){ struct stat filestat; int ret; char *rdir; rdir = GNUNET_expand_file_name (ectx, fil); if (rdir == NULL) return GNUNET_SYSERR; ret = STAT (rdir, &filestat); if (ret != 0) { if (errno != ENOENT) { GNUNET_GE_LOG_STRERROR_FILE (ectx, GNUNET_GE_WARNING | GNUNET_GE_USER | GNUNET_GE_ADMIN | GNUNET_GE_REQUEST, "stat", rdir); GNUNET_free (rdir); return GNUNET_SYSERR; } GNUNET_free (rdir); return GNUNET_NO; } if (!S_ISREG (filestat.st_mode)) { GNUNET_free (rdir); return GNUNET_NO; } if (ACCESS (rdir, R_OK) < 0) { GNUNET_GE_LOG_STRERROR_FILE (ectx, GNUNET_GE_WARNING | GNUNET_GE_USER | GNUNET_GE_ADMIN | GNUNET_GE_REQUEST, "access", rdir); GNUNET_free (rdir); return GNUNET_SYSERR; } GNUNET_free (rdir); return GNUNET_YES;}/** * Implementation of "mkdir -p" * @param dir the directory to create * @returns GNUNET_OK on success, GNUNET_SYSERR on failure */intGNUNET_disk_directory_create (struct GNUNET_GE_Context *ectx, const char *dir){ char *rdir; int len; int pos; int ret = GNUNET_OK; rdir = GNUNET_expand_file_name (ectx, dir); if (rdir == NULL) return GNUNET_SYSERR; len = strlen (rdir);#ifndef MINGW pos = 1; /* skip heading '/' */#else /* Local or Network path? */ if (strncmp (rdir, "\\\\", 2) == 0) { pos = 2; while (rdir[pos]) { if (rdir[pos] == '\\') { pos++; break; } pos++; } } else { pos = 3; /* strlen("C:\\") */ }#endif while (pos <= len) { if ((rdir[pos] == DIR_SEPARATOR) || (pos == len)) { rdir[pos] = '\0'; ret = GNUNET_disk_directory_test (ectx, rdir); if (ret == GNUNET_SYSERR) { GNUNET_free (rdir); return GNUNET_SYSERR; } if (ret == GNUNET_NO) {#ifndef MINGW ret = mkdir (rdir, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH); /* 755 */#else ret = mkdir (rdir);#endif if ((ret != 0) && (errno != EEXIST)) { GNUNET_GE_LOG_STRERROR_FILE (ectx, GNUNET_GE_ERROR | GNUNET_GE_USER | GNUNET_GE_BULK, "mkdir", rdir); GNUNET_free (rdir); return GNUNET_SYSERR; } } rdir[pos] = DIR_SEPARATOR;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -